diff --git a/.github/workflows/digidoc4j-verify.yml b/.github/workflows/digidoc4j-verify.yml index cc0af1924..f15e52119 100644 --- a/.github/workflows/digidoc4j-verify.yml +++ b/.github/workflows/digidoc4j-verify.yml @@ -6,7 +6,11 @@ name: Digidoc4j CI with Maven on: push: branches: - - main + - master + - develop + pull_request: + branches: + - master - develop jobs: @@ -14,7 +18,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-18.04] + os: [ ubuntu-20.04 ] java: [ 8, 11, 15 ] steps: - uses: actions/checkout@v2 @@ -25,4 +29,4 @@ jobs: - name: Build with Maven env: TZ: Europe/Helsinki - run: mvn clean verify -q -"Dgpg.skip" \ No newline at end of file + run: mvn clean verify -q -"Dgpg.skip" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5774f2729..000000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -dist: bionic -language: java -jdk: -- openjdk8 -- openjdk10 -branches: - only: - - develop - - master - - 3.x.x -before_install: -- export TZ=Europe/Helsinki -install: true -script: mvn clean verify -q -Dgpg.skip -notifications: - email: - recipients: - - aare.nurm@nortal.com - - siim.suu@nortal.com - on_success: change - on_failure: always diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index c11d64cdc..b620d0777 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,6 +1,32 @@ DigiDoc4J Java library release notes ------------------------------------ +Release 4.2.0 +------------------ +Summary of the major changes since 4.1.1 +------------------------------------------ +* ZIP-bomb attack protection +* If not specified, create ASiC-E (instead of BDOC) containers by default +* Search BDOC TM signature OCSP certificate from OCSP token first and then from the unsigned properties of the signature +* Limitations for empty (0-byte) datafiles: + - Adding empty datafiles to containers is not permitted; signing containers containing empty datafiles is not permitted + - Validating containers containing empty datafiles adds additional container warnings +* Changes in validation policies +* Upgrade of TSL TLS truststore +* Dependencies update +* Bug fixes + +Known issues +------------ +* We have noticed a decrease in performance with the introduction of properly accessing AIA certificate resources +* Opening a container that contains signatures, triggers TSL loading (TSL lazy loading does not work as expected) +* While upgrading from versions older than 2.1.1 be sure that your integration : + - doesn't use Xalan or XercesImpl dependencies + - uses a patched Java version (JDK8 or higher) + Xalan and XercesImpl were used to patch XML vulnerabilities in older java versions. They should be discarded with higher versions because they override default Java XML security. + If it is not possible to remove Xalan, then you can set your system property to override TransformerFactory : System.setProperty("javax.xml.transform.TransformerFactory","com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); + + Release 4.1.1 ------------------ Signer certificate for the EU List of eIDAS Trusted Lists (LOTL) was changed on 25.03.2021. This resulted in failure to sign or validate signatures with DD4J version 4.1.0. diff --git a/ddoc4j/pom.xml b/ddoc4j/pom.xml index 68aba26ac..933877488 100644 --- a/ddoc4j/pom.xml +++ b/ddoc4j/pom.xml @@ -6,7 +6,7 @@ org.digidoc4j ddoc4j jar - 4.1.1 + 4.2.0 DDoc4J DDoc4J is Java Library for validating DDOC documents. It's not recommended to use it directly but rather through DigiDoc4J's API. @@ -15,7 +15,7 @@ digidoc4j-parent org.digidoc4j - 4.1.1 + 4.2.0 diff --git a/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/BouncyCastleNotaryFactory.java b/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/BouncyCastleNotaryFactory.java index 36af57823..7ae0dfc73 100644 --- a/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/BouncyCastleNotaryFactory.java +++ b/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/BouncyCastleNotaryFactory.java @@ -324,7 +324,7 @@ public Notary parseAndVerifyResponse(Signature sig, Notary not) private String responderIDtoString(BasicOCSPResp basResp) { if(basResp != null) { ResponderID respid = basResp.getResponderId().toASN1Primitive(); - Object o = ((DERTaggedObject)respid.toASN1Object()).getObject(); + Object o = ((DERTaggedObject)respid.toASN1Primitive()).getObject(); if(o instanceof org.bouncycastle.asn1.DEROctetString) { org.bouncycastle.asn1.DEROctetString oc = (org.bouncycastle.asn1.DEROctetString)o; return "byKey: " + SignedDoc.bin2hex(oc.getOctets()); @@ -387,4 +387,4 @@ public void init() } } -} \ No newline at end of file +} diff --git a/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/SAXDigiDocFactory.java b/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/SAXDigiDocFactory.java index 383da0a33..6f6be18e2 100644 --- a/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/SAXDigiDocFactory.java +++ b/ddoc4j/src/main/java/org/digidoc4j/ddoc/factory/SAXDigiDocFactory.java @@ -984,7 +984,12 @@ public void startElement(String namespaceURI, String lName, String qName, Attrib String Id = attrs.getValue("Id"); if(Id != null) ref.setId(Id); - ref.setUri(ConvertUtils.unescapeXmlSymbols(ConvertUtils.uriDecode(URI))); + if (URI==null) { + DigiDocException ex = new DigiDocException(DigiDocException.ERR_DATA_FILE_ATTR_VALUE,"URI Attribute value is required", null); + handleSAXError(ex); + } else { + ref.setUri(ConvertUtils.unescapeXmlSymbols(ConvertUtils.uriDecode(URI))); + } String sType = attrs.getValue("Type"); if(sType != null) ref.setType(sType); diff --git a/digidoc4j/pom.xml b/digidoc4j/pom.xml index d35157928..577f8a39f 100644 --- a/digidoc4j/pom.xml +++ b/digidoc4j/pom.xml @@ -7,7 +7,7 @@ org.digidoc4j digidoc4j jar - 4.1.1 + 4.2.0 DigiDoc4j DigiDoc4j is a Java library for digitally signing documents and creating digital signature containers @@ -18,12 +18,14 @@ digidoc4j-parent org.digidoc4j - 4.1.1 + 4.2.0 + 2.2 1.2.3 - 4.13.1 + 2.12.3 + 4.13.2 org.digidoc4j.dss 5.7.d4j.2 ${project.build.directory}/build/util @@ -43,7 +45,7 @@ ddoc4j org.digidoc4j - 4.1.1 + 4.2.0 @@ -72,7 +74,7 @@ org.apache.commons commons-lang3 - 3.11 + 3.12.0 commons-logging @@ -92,7 +94,7 @@ org.apache.santuario xmlsec - 2.1.5 + 2.1.6 org.codehaus.woodstox @@ -103,7 +105,7 @@ org.yaml snakeyaml - 1.27 + 1.28 org.slf4j @@ -199,6 +201,18 @@ ${dss.groupId} dss-pades-pdfbox ${dss.version} + + + org.apache.pdfbox + pdfbox + + + + + + org.apache.pdfbox + pdfbox + 2.0.23 ${dss.groupId} @@ -229,7 +243,7 @@ org.glassfish.jaxb jaxb-runtime - 2.3.3 + 2.3.4 javax.activation @@ -239,7 +253,7 @@ com.sun.xml.bind jaxb-impl - 2.3.3 + 2.3.4 com.sun.xml.bind @@ -261,19 +275,19 @@ org.hamcrest hamcrest-core - 2.2 + ${hamcrest.version} test com.jcabi jcabi-matchers - 1.4 + 1.5.3 test org.mockito mockito-core - 3.6.0 + 3.10.0 test @@ -297,7 +311,7 @@ org.hamcrest hamcrest-library - 2.2 + ${hamcrest.version} test @@ -315,19 +329,19 @@ com.fasterxml.jackson.core jackson-databind - 2.11.3 + ${jackson.version} test com.fasterxml.jackson.core jackson-core - 2.11.3 + ${jackson.version} test com.fasterxml.jackson.core jackson-annotations - 2.11.3 + ${jackson.version} test @@ -345,7 +359,7 @@ org.json json - 20200518 + 20210307 test diff --git a/digidoc4j/src/main/java/org/digidoc4j/Configuration.java b/digidoc4j/src/main/java/org/digidoc4j/Configuration.java index 1d61b773a..1518a4372 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/Configuration.java +++ b/digidoc4j/src/main/java/org/digidoc4j/Configuration.java @@ -136,6 +136,7 @@ *
  • SUPPORTED_SSL_PROTOCOLS: list of supported SSL protocols (by default uses implementation defaults)
  • *
  • SUPPORTED_SSL_CIPHER_SUITES: list of supported SSL cipher suites (by default uses implementation defaults)
  • *
  • ALLOWED_TS_AND_OCSP_RESPONSE_DELTA_IN_MINUTES: Allowed delay between timestamp and OCSP response in minutes.
  • + *
  • TEMP_FILE_MAX_AGE: Maximum age in milliseconds till TEMP files are deleted (works only when saving container).
  • *
  • ALLOW_UNSAFE_INTEGER: Allows to use unsafe Integer because of few applications still struggle with the * ASN.1 BER encoding rules for an INTEGER as described in: * {@link https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf. } @@ -645,6 +646,24 @@ public boolean getUseNonceForAiaOcspByCN(String cn) { return true; } + /** + * Set temp file max age in millis + * + * @param tempFileMaxAgeInMillis max age in millis + */ + public void setTempFileMaxAge(long tempFileMaxAgeInMillis) { + this.setConfigurationParameter(ConfigurationParameter.TempFileMaxAgeInMillis, String.valueOf(tempFileMaxAgeInMillis)); + } + + /** + * Get temp file max age + * + * @return temp file max age in millis + */ + public long getTempFileMaxAge() { + return this.getConfigurationParameter(ConfigurationParameter.TempFileMaxAgeInMillis, Long.class); + } + /** * Set HTTP connection timeout * @@ -1167,10 +1186,10 @@ public boolean isProxyOfTypeFor(ExternalConnectionType connectionType, Protocol */ public boolean isSslConfigurationEnabled() { return StringUtils.isNotBlank(this.getSslKeystorePath()) || - StringUtils.isNotBlank(this.getSslTruststorePath()) || - StringUtils.isNotBlank(this.getSslProtocol()) || - CollectionUtils.isNotEmpty(this.getSupportedSslProtocols()) || - CollectionUtils.isNotEmpty(this.getSupportedSslCipherSuites()); + StringUtils.isNotBlank(this.getSslTruststorePath()) || + StringUtils.isNotBlank(this.getSslProtocol()) || + CollectionUtils.isNotEmpty(this.getSupportedSslProtocols()) || + CollectionUtils.isNotEmpty(this.getSupportedSslCipherSuites()); } /** @@ -1181,10 +1200,10 @@ public boolean isSslConfigurationEnabled() { */ public boolean isSslConfigurationEnabledFor(ExternalConnectionType connectionType) { return StringUtils.isNotBlank(this.getSslKeystorePathFor(connectionType)) || - StringUtils.isNotBlank(this.getSslTruststorePathFor(connectionType)) || - StringUtils.isNotBlank(this.getSslProtocolFor(connectionType)) || - CollectionUtils.isNotEmpty(this.getSupportedSslProtocolsFor(connectionType)) || - CollectionUtils.isNotEmpty(this.getSupportedSslCipherSuitesFor(connectionType)); + StringUtils.isNotBlank(this.getSslTruststorePathFor(connectionType)) || + StringUtils.isNotBlank(this.getSslProtocolFor(connectionType)) || + CollectionUtils.isNotEmpty(this.getSupportedSslProtocolsFor(connectionType)) || + CollectionUtils.isNotEmpty(this.getSupportedSslCipherSuitesFor(connectionType)); } /** @@ -1474,7 +1493,7 @@ public String getSslProtocolFor(ExternalConnectionType connectionType) { */ public void setSupportedSslProtocols(List supportedSslProtocols) { this.setConfigurationParameter(ConfigurationParameter.SupportedSslProtocols, Optional.ofNullable(supportedSslProtocols) - .map(l -> l.toArray(new String[l.size()])).orElse(null)); + .map(l -> l.toArray(new String[l.size()])).orElse(null)); } /** @@ -1486,7 +1505,7 @@ public void setSupportedSslProtocols(List supportedSslProtocols) { */ public void setSupportedSslProtocolsFor(ExternalConnectionType connectionType, List supportedSslProtocols) { this.setConfigurationParameter(connectionType.mapToSpecificParameter(ConfigurationParameter.SupportedSslProtocols), - Optional.ofNullable(supportedSslProtocols).map(l -> l.toArray(new String[l.size()])).orElse(null)); + Optional.ofNullable(supportedSslProtocols).map(l -> l.toArray(new String[l.size()])).orElse(null)); } /** @@ -1528,7 +1547,7 @@ public void setSupportedSslCipherSuites(List supportedSslCipherSuites) { */ public void setSupportedSslCipherSuitesFor(ExternalConnectionType connectionType, List supportedSslCipherSuites) { this.setConfigurationParameter(connectionType.mapToSpecificParameter(ConfigurationParameter.SupportedSslCipherSuites), - Optional.ofNullable(supportedSslCipherSuites).map(l -> l.toArray(new String[l.size()])).orElse(null)); + Optional.ofNullable(supportedSslCipherSuites).map(l -> l.toArray(new String[l.size()])).orElse(null)); } /** @@ -1690,9 +1709,9 @@ public Configuration copy() { return copyConfiguration; } - /* - * RESTRICTED METHODS - */ + /* + * RESTRICTED METHODS + */ protected ConfigurationRegistry getRegistry() { return this.registry; @@ -1710,6 +1729,8 @@ private void initDefaultValues() { String.valueOf(Constant.ONE_DAY_IN_MINUTES)); this.setConfigurationParameter(ConfigurationParameter.TslCacheExpirationTimeInMillis, String.valueOf(Constant.ONE_DAY_IN_MILLISECONDS)); + this.setConfigurationParameter(ConfigurationParameter.TempFileMaxAgeInMillis, + String.valueOf(Constant.ONE_DAY_IN_MILLISECONDS)); this.setConfigurationParameter(ConfigurationParameter.AllowedTimestampAndOCSPResponseDeltaInMinutes, "15"); this.setConfigurationParameter(ConfigurationParameter.SignatureProfile, Constant.Default.SIGNATURE_PROFILE); this.setConfigurationParameter(ConfigurationParameter.SignatureDigestAlgorithm, @@ -1774,6 +1795,7 @@ private void loadInitialConfigurationValues() { ConfigurationParameter.OcspAccessCertificateFile); this.setConfigurationParameterFromFile("DIGIDOC_PKCS12_PASSWD", ConfigurationParameter.OcspAccessCertificatePassword); + this.setConfigurationParameterFromFile("TEMP_FILE_MAX_AGE", ConfigurationParameter.TempFileMaxAgeInMillis); this.setConfigurationParameterFromFile("CONNECTION_TIMEOUT", ConfigurationParameter.ConnectionTimeoutInMillis); this.setConfigurationParameterFromFile("SOCKET_TIMEOUT", ConfigurationParameter.SocketTimeoutInMillis); this.setConfigurationParameterFromFile("SIGN_OCSP_REQUESTS", ConfigurationParameter.SignOcspRequests); @@ -2020,9 +2042,9 @@ private void loadYamlAiaOCSPs(LinkedHashMap configurationFromYam } if (CollectionUtils.isNotEmpty(aiaOcspsFromYaml)) { List> entryPairs = Arrays.asList( - Pair.of("ISSUER_CN", ConfigurationParameter.issuerCn), - Pair.of("OCSP_SOURCE", ConfigurationParameter.aiaOcspSource), - Pair.of("USE_NONCE", ConfigurationParameter.useNonce) + Pair.of("ISSUER_CN", ConfigurationParameter.issuerCn), + Pair.of("OCSP_SOURCE", ConfigurationParameter.aiaOcspSource), + Pair.of("USE_NONCE", ConfigurationParameter.useNonce) ); for (int i = 0; i < aiaOcspsFromYaml.size(); i++) { Map aiaOcspFromYaml = aiaOcspsFromYaml.get(i); @@ -2101,7 +2123,7 @@ private void reportFileParseErrors() { } } - private void loadYamlOcspResponders(){ + private void loadYamlOcspResponders() { List responders = getStringListParameterFromFile("ALLOWED_OCSP_RESPONDERS_FOR_TM"); if (responders != null) { String[] respondersValue = responders.toArray(new String[0]); diff --git a/digidoc4j/src/main/java/org/digidoc4j/ConfigurationParameter.java b/digidoc4j/src/main/java/org/digidoc4j/ConfigurationParameter.java index 246c22836..44b60f816 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/ConfigurationParameter.java +++ b/digidoc4j/src/main/java/org/digidoc4j/ConfigurationParameter.java @@ -97,7 +97,9 @@ public enum ConfigurationParameter { TspSslTruststorePassword("TSP_SSL_TRUSTSTORE_PASSWORD"), TspSslProtocol("TSP_SSL_PROTOCOL"), TspSupportedSslProtocols("TSP_SUPPORTED_SSL_PROTOCOLS"), - TspSupportedSslCipherSuites("TSP_SUPPORTED_SSL_CIPHER_SUITES"); + TspSupportedSslCipherSuites("TSP_SUPPORTED_SSL_CIPHER_SUITES"), + TempFileMaxAgeInMillis; + final String fileKey; diff --git a/digidoc4j/src/main/java/org/digidoc4j/ContainerBuilder.java b/digidoc4j/src/main/java/org/digidoc4j/ContainerBuilder.java index 8b15a4b6e..6e7234795 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/ContainerBuilder.java +++ b/digidoc4j/src/main/java/org/digidoc4j/ContainerBuilder.java @@ -71,12 +71,12 @@ public abstract class ContainerBuilder { private DataFile timeStampToken; /** - * Create a new BDoc container builder. + * Create a new ASICE container builder. * - * @return builder for creating or opening a BDOC(ASICE) container. + * @return builder for creating or opening a ASICE container. */ public static ContainerBuilder aContainer() { - return aContainer(Container.DocumentType.BDOC); + return aContainer(Container.DocumentType.ASICE); } /** diff --git a/digidoc4j/src/main/java/org/digidoc4j/ContainerValidationResult.java b/digidoc4j/src/main/java/org/digidoc4j/ContainerValidationResult.java index 87c714ad2..ee4654cd6 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/ContainerValidationResult.java +++ b/digidoc4j/src/main/java/org/digidoc4j/ContainerValidationResult.java @@ -19,4 +19,11 @@ public interface ContainerValidationResult extends SignatureValidationResult { */ List getContainerErrors(); + /** + * Get list container related warnings. + * + * @return List of exceptions + */ + List getContainerWarnings(); + } diff --git a/digidoc4j/src/main/java/org/digidoc4j/DataFile.java b/digidoc4j/src/main/java/org/digidoc4j/DataFile.java index 0f5ca4391..fdcf469b7 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/DataFile.java +++ b/digidoc4j/src/main/java/org/digidoc4j/DataFile.java @@ -18,6 +18,7 @@ import eu.europa.esig.dss.model.FileDocument; import eu.europa.esig.dss.model.InMemoryDocument; import eu.europa.esig.dss.model.MimeType; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.digidoc4j.exceptions.DigiDoc4JException; import org.digidoc4j.exceptions.InvalidDataFileException; @@ -26,8 +27,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -36,6 +35,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.OptionalLong; /** * Data file wrapper providing methods for handling signed files or files to be signed in Container. @@ -73,9 +73,7 @@ public DataFile(String path, String mimeType) { */ public DataFile(byte[] data, String fileName, String mimeType) { logger.debug("File name: " + fileName + ", mime type: " + mimeType); - ByteArrayInputStream stream = new ByteArrayInputStream(data); - document = new InMemoryDocument(stream, fileName, getMimeType(mimeType)); - IOUtils.closeQuietly(stream); + document = new InMemoryDocument(data.clone(), fileName, getMimeType(mimeType)); } /** @@ -105,7 +103,7 @@ public DataFile() { protected MimeType getMimeType(String mimeType) { try { MimeType mimeTypeCode = MimeType.fromMimeTypeString(mimeType); - logger.debug("Mime type: ", mimeTypeCode); + logger.debug("Mime type: {}", mimeTypeCode); return mimeTypeCode; } catch (DSSException e) { logger.error(e.getMessage()); @@ -168,7 +166,7 @@ byte[] calculateDigestInternal(DigestAlgorithm digestAlgorithm) { */ public String getName() { String documentName = document.getName(); - String name = new File(documentName).getName(); + String name = FilenameUtils.getName(documentName); logger.trace("File name: for document " + documentName + " is " + name); return name; } @@ -189,20 +187,55 @@ public String getId() { * @return file size in bytes */ public long getFileSize() { - long fileSize; + OptionalLong fileBackedSize = getFileSizeIfBackedByFile(); + if (fileBackedSize.isPresent()) { + return fileBackedSize.getAsLong(); + } + long fileSize = 0L; + try (InputStream inputStream = getStream()) { + // Read the entire stream, but do not build yet another byte[] to hold the entire contents. Just skip and count the bytes. + // InputStream.skip(long) is not reliable to count the actual number of bytes available via an input stream. + byte[] skipBuffer = new byte[IOUtils.DEFAULT_BUFFER_SIZE]; + int bytesRead; + while ((bytesRead = inputStream.read(skipBuffer)) > 0) { + fileSize += bytesRead; + } + } catch (IOException e) { + throw new TechnicalException("Error reading document bytes: " + e.getMessage(), e); + } + logger.debug("File document size: " + fileSize); + return fileSize; + } + + /** + * Returns {@code true} if the data file size is 0 bytes. + * + * @return {@code true} if the data file is empty + */ + public boolean isFileEmpty() { + OptionalLong fileBackedSize = getFileSizeIfBackedByFile(); + if (fileBackedSize.isPresent()) { + return (fileBackedSize.getAsLong() < 1L); + } + try (InputStream inputStream = getStream()) { + return (inputStream.read() < 0); // read() returns -1 if no bytes to read + } catch (IOException e) { + throw new TechnicalException("Error reading document bytes: " + e.getMessage(), e); + } + } + + private OptionalLong getFileSizeIfBackedByFile() { if (document instanceof StreamDocument || document instanceof FileDocument) { try { - fileSize = Files.size(Paths.get(document.getAbsolutePath())); + long fileSize = Files.size(Paths.get(document.getAbsolutePath())); logger.debug("Document size: " + fileSize); - return fileSize; + return OptionalLong.of(fileSize); } catch (IOException e) { logger.error(e.getMessage()); throw new DigiDoc4JException(e); } } - fileSize = getBytes().length; - logger.debug("File document size: " + fileSize); - return fileSize; + return OptionalLong.empty(); } /** diff --git a/digidoc4j/src/main/java/org/digidoc4j/DigestDataFile.java b/digidoc4j/src/main/java/org/digidoc4j/DigestDataFile.java index fb2e0d3e4..3b624f798 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/DigestDataFile.java +++ b/digidoc4j/src/main/java/org/digidoc4j/DigestDataFile.java @@ -4,6 +4,7 @@ import org.apache.commons.codec.binary.Base64; import org.digidoc4j.exceptions.InvalidDataFileException; +import org.digidoc4j.exceptions.NotSupportedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,4 +68,15 @@ public String getContentType() { public void setContentType(String contentType) { this.contentType = contentType; } + + @Override + public long getFileSize() { + throw new NotSupportedException("Querying size of digest datafile is not supported"); + } + + @Override + public boolean isFileEmpty() { + return false; + } + } diff --git a/digidoc4j/src/main/java/org/digidoc4j/SignatureToken.java b/digidoc4j/src/main/java/org/digidoc4j/SignatureToken.java index c8242bf9f..fa51308a2 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/SignatureToken.java +++ b/digidoc4j/src/main/java/org/digidoc4j/SignatureToken.java @@ -33,4 +33,5 @@ public interface SignatureToken { */ byte[] sign(DigestAlgorithm digestAlgorithm, byte[] dataToSign); + void close(); } diff --git a/digidoc4j/src/main/java/org/digidoc4j/exceptions/InvalidKeyException.java b/digidoc4j/src/main/java/org/digidoc4j/exceptions/InvalidKeyException.java new file mode 100644 index 000000000..07d23b0a9 --- /dev/null +++ b/digidoc4j/src/main/java/org/digidoc4j/exceptions/InvalidKeyException.java @@ -0,0 +1,13 @@ +package org.digidoc4j.exceptions; + +public class InvalidKeyException extends DigiDoc4JException { + + public InvalidKeyException(String message) { + super(message); + } + + public InvalidKeyException(Throwable e) { + super(e); + } + +} diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/AbstractContainerValidationResult.java b/digidoc4j/src/main/java/org/digidoc4j/impl/AbstractContainerValidationResult.java new file mode 100644 index 000000000..882ca81ca --- /dev/null +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/AbstractContainerValidationResult.java @@ -0,0 +1,40 @@ +package org.digidoc4j.impl; + +import org.digidoc4j.ContainerValidationResult; +import org.digidoc4j.exceptions.DigiDoc4JException; + +import java.util.ArrayList; +import java.util.List; + +public abstract class AbstractContainerValidationResult extends AbstractSignatureValidationResult implements ContainerValidationResult { + + protected List containerErrors = new ArrayList<>(); + protected List containerWarnings = new ArrayList<>(); + + @Override + public List getContainerErrors() { + return containerErrors; + } + + public void addContainerErrors(List containerErrors) { + this.containerErrors = concatenate(this.containerErrors, containerErrors); + } + + public void setContainerErrors(List containerErrors) { + this.containerErrors = containerErrors; + } + + @Override + public List getContainerWarnings() { + return containerWarnings; + } + + public void addContainerWarnings(List containerWarnings) { + this.containerWarnings = concatenate(this.containerWarnings, containerWarnings); + } + + public void setContainerWarnings(List containerWarnings) { + this.containerWarnings = containerWarnings; + } + +} diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/AbstractValidationResult.java b/digidoc4j/src/main/java/org/digidoc4j/impl/AbstractValidationResult.java index 93f23b9d3..ae82f20b4 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/AbstractValidationResult.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/AbstractValidationResult.java @@ -2,6 +2,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.collections4.CollectionUtils; import org.digidoc4j.Configuration; @@ -78,6 +81,10 @@ public List getErrors() { return errors; } + public void addErrors(List errors) { + this.errors = concatenate(this.errors, errors); + } + public void setErrors(List errors) { this.errors = errors; } @@ -87,8 +94,19 @@ public List getWarnings() { return warnings; } + public void addWarnings(List warnings) { + this.warnings = concatenate(this.warnings, warnings); + } + public void setWarnings(List warnings) { this.warnings = warnings; } + protected static List concatenate(List first, List second) { + return Stream.concat( + Optional.ofNullable(first).map(List::stream).orElseGet(Stream::empty), + Optional.ofNullable(second).map(List::stream).orElseGet(Stream::empty) + ).collect(Collectors.toList()); + } + } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/ConfigurationSingeltonHolder.java b/digidoc4j/src/main/java/org/digidoc4j/impl/ConfigurationSingeltonHolder.java index 1f7edf3ab..69cf11a62 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/ConfigurationSingeltonHolder.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/ConfigurationSingeltonHolder.java @@ -26,18 +26,22 @@ public class ConfigurationSingeltonHolder { * A thread-safe way of getting a single configuration object. */ public static Configuration getInstance() { - if (configuration == null) { + // For correct usage of double-checked locking for lazy initialization in Java, + // see: https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java + Configuration localConfigurationReference = configuration; + if (localConfigurationReference == null) { //Using double-checked locking for ensuring that no other thread has started initializing Configuration object already synchronized (ConfigurationSingeltonHolder.class) { - if (configuration == null) { + localConfigurationReference = configuration; + if (localConfigurationReference == null) { logger.info("Creating a new configuration instance"); - configuration = new Configuration(); + configuration = localConfigurationReference = new Configuration(); } } } else { logger.info("Using existing configuration instance"); } - return configuration; + return localConfigurationReference; } /** diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/OCSPCertificateValidator.java b/digidoc4j/src/main/java/org/digidoc4j/impl/OCSPCertificateValidator.java index a48f505e4..c3c6d2666 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/OCSPCertificateValidator.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/OCSPCertificateValidator.java @@ -10,9 +10,11 @@ package org.digidoc4j.impl; +import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.model.x509.Token; +import eu.europa.esig.dss.model.x509.X500PrincipalHelper; import eu.europa.esig.dss.spi.DSSUtils; import eu.europa.esig.dss.spi.x509.CertificateSource; -import eu.europa.esig.dss.model.x509.CertificateToken; import eu.europa.esig.dss.spi.x509.revocation.ocsp.OCSPSource; import org.apache.commons.collections4.CollectionUtils; import org.digidoc4j.CertificateValidator; @@ -25,7 +27,7 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import java.util.List; +import java.util.Collections; import java.util.Set; /** @@ -83,26 +85,40 @@ private CertificateToken getIssuerCertificateToken(X509Certificate certificate) .getDSSIdAsString(), e); } throw CertificateValidationException.of(CertificateValidationStatus.UNTRUSTED, - "Failed to parse issuer certificate token. Not all intermediate certificates added into OCSP."); + "Failed to parse issuer certificate token. Not all intermediate certificates added into OCSP."); } private CertificateToken getIssuerForCertificateToken(CertificateToken certificateToken) { Set tokens = this.getIssuerFromCertificateSource(certificateToken); if (tokens.size() != 1) { throw new IllegalStateException(String.format("<%s> matching certificate tokens found from certificate source", - tokens.size())); + tokens.size())); } return tokens.iterator().next(); } private Set getIssuerFromCertificateSource(CertificateToken certificateToken) { - Set issuers = this.configuration.getTSL().getBySubject(certificateToken.getIssuer()); + Set issuers = getIssuers(certificateToken, this.configuration.getTSL()); if (CollectionUtils.isEmpty(issuers)) { - issuers = this.certificateSource.getBySubject(certificateToken.getIssuer()); + issuers = getIssuers(certificateToken, this.certificateSource); } return issuers; } + private Set getIssuers(final Token token, CertificateSource certificateSource) { + if (token.getPublicKeyOfTheSigner() != null) { + return certificateSource.getByPublicKey(token.getPublicKeyOfTheSigner()); + } else if (token.getIssuerX500Principal() != null) { + Set potentialIssuers = certificateSource.getBySubject(new X500PrincipalHelper(token.getIssuerX500Principal())); + for (CertificateToken potentialIssuer : potentialIssuers) { + if (token.isSignedBy(potentialIssuer)) { + return certificateSource.getByPublicKey(potentialIssuer.getPublicKey()); + } + } + } + return Collections.emptySet(); + } + /* * ACCESSORS */ diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/SKOnlineOCSPSource.java b/digidoc4j/src/main/java/org/digidoc4j/impl/SKOnlineOCSPSource.java index 801988e5f..ed2dd2734 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/SKOnlineOCSPSource.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/SKOnlineOCSPSource.java @@ -10,6 +10,7 @@ package org.digidoc4j.impl; +import eu.europa.esig.dss.DomUtils; import eu.europa.esig.dss.enumerations.CertificateStatus; import eu.europa.esig.dss.enumerations.DigestAlgorithm; import eu.europa.esig.dss.model.DSSException; @@ -17,11 +18,13 @@ import eu.europa.esig.dss.spi.DSSRevocationUtils; import eu.europa.esig.dss.spi.DSSUtils; import eu.europa.esig.dss.spi.client.http.DataLoader; +import eu.europa.esig.dss.spi.x509.ResponderId; import eu.europa.esig.dss.spi.x509.revocation.ocsp.OCSPSource; import eu.europa.esig.dss.spi.x509.revocation.ocsp.OCSPToken; import eu.europa.esig.dss.token.DSSPrivateKeyEntry; import eu.europa.esig.dss.token.KSPrivateKeyEntry; import eu.europa.esig.dss.token.Pkcs12SignatureToken; +import eu.europa.esig.dss.utils.Utils; import org.apache.commons.collections4.CollectionUtils; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; @@ -117,7 +120,7 @@ public String getAccessLocation(X509Certificate certificate) { if (getConfiguration() != null) { return getConfiguration().getOcspSource(); } - return Constant.Test.OCSP_SOURCE; + throw new ConfigurationException("Configuration needed for OCSP request"); } /* @@ -201,13 +204,14 @@ private void validateOCSPResponseStatus(int ocspResponseStatus, String serviceUr } } - private void verifyOCSPResponse(BasicOCSPResp response) throws IOException { + protected void verifyOCSPResponse(BasicOCSPResp response) throws IOException { + ResponderId responderId = DSSRevocationUtils.getDSSResponderId(response.getResponderId()); List holders = Arrays.asList(response.getCerts()); if (CollectionUtils.isNotEmpty(holders)) { boolean hasOcspResponderCert = false; for (X509CertificateHolder holder : holders) { CertificateToken token = DSSUtils.loadCertificate(holder.getEncoded()); - if (isOcspResponderCertificate(token)) { + if (responderId.isRelatedToCertificate(token)) { hasOcspResponderCert = true; } else { continue; @@ -217,7 +221,7 @@ private void verifyOCSPResponse(BasicOCSPResp response) throws IOException { } if (!hasOcspResponderCert) { throw CertificateValidationException.of(CertificateValidationStatus.TECHNICAL, - "None of the OCSP response certificates does have 'OCSPSigning' extended key usage"); + "OCSP responderId is not related to any certificates"); } } else { if (!this.configuration.isTest()) { @@ -226,15 +230,6 @@ private void verifyOCSPResponse(BasicOCSPResp response) throws IOException { } } - protected boolean isOcspResponderCertificate(CertificateToken token) { - try { - return token.getCertificate().getExtendedKeyUsage() != null && token.getCertificate().getExtendedKeyUsage().contains(OID_OCSP_SIGNING); - } catch (CertificateParsingException e) { - throw CertificateValidationException.of(CertificateValidationStatus.TECHNICAL, - String.format("Error on verifying 'OCSPSigning' extended key usage for OCSP response certificate <%s>", token.getDSSIdAsString()), e); - } - } - protected void verifyOcspResponderCertificate(CertificateToken token, Date producedAt) { verifyValidityDate(token, producedAt); if (!configuration.getTSL().isTrusted(token)) { diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/SignatureFinalizer.java b/digidoc4j/src/main/java/org/digidoc4j/impl/SignatureFinalizer.java index 19ae20515..f2aed3d9a 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/SignatureFinalizer.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/SignatureFinalizer.java @@ -17,6 +17,7 @@ import org.digidoc4j.Signature; import org.digidoc4j.SignatureBuilder; import org.digidoc4j.SignatureParameters; +import org.digidoc4j.exceptions.InvalidDataFileException; import java.io.Serializable; import java.util.List; @@ -32,6 +33,7 @@ public abstract class SignatureFinalizer implements Serializable { protected Configuration configuration; public SignatureFinalizer(List dataFiles, SignatureParameters signatureParameters, Configuration configuration) { + verifyDataFilesNotEmpty(dataFiles); this.dataFiles = dataFiles; this.signatureParameters = signatureParameters; this.configuration = configuration; @@ -74,4 +76,19 @@ public Configuration getConfiguration() { public SignatureParameters getSignatureParameters() { return signatureParameters; } + + private static void verifyDataFilesNotEmpty(List dataFiles) { + dataFiles.stream() + .filter(DataFile::isFileEmpty) + .map(dataFile -> "Cannot sign empty datafile: " + dataFile.getName()) + .map(InvalidDataFileException::new) + .reduce((e1, e2) -> { + e1.addSuppressed(e2); + return e1; + }) + .ifPresent(e -> { + throw e; + }); + } + } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainer.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainer.java index ac1a9f903..59a0a9d83 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainer.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainer.java @@ -11,6 +11,7 @@ package org.digidoc4j.impl.asic; import eu.europa.esig.dss.model.DSSDocument; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.digidoc4j.Configuration; @@ -28,10 +29,13 @@ import org.digidoc4j.exceptions.DataFileNotFoundException; import org.digidoc4j.exceptions.DigiDoc4JException; import org.digidoc4j.exceptions.DuplicateDataFileException; +import org.digidoc4j.exceptions.InvalidDataFileException; import org.digidoc4j.exceptions.InvalidSignatureException; import org.digidoc4j.exceptions.NotSupportedException; import org.digidoc4j.exceptions.RemovingDataFileException; +import org.digidoc4j.exceptions.SignatureNotFoundException; import org.digidoc4j.exceptions.TechnicalException; +import org.digidoc4j.impl.AbstractContainerValidationResult; import org.digidoc4j.impl.AbstractValidationResult; import org.digidoc4j.impl.asic.asice.AsicEContainerValidator; import org.digidoc4j.impl.asic.asice.AsicESignature; @@ -57,6 +61,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; /** * Created by Andrei on 7.11.2017. @@ -166,30 +171,32 @@ public ContainerValidationResult validate() { } protected ContainerValidationResult validateContainer() { + ContainerValidationResult containerValidationResult; if (this.timeStampToken != null) { - return this.validateTimestampToken(); + containerValidationResult = this.validateTimestampToken(); } else { + AsicEContainerValidator containerValidator; if (!this.isNewContainer()) { if (DocumentType.BDOC.name().equalsIgnoreCase(this.containerType)) { - return new BDocContainerValidator(this.containerParseResult, this.getConfiguration(), - !this.dataFilesHaveChanged).validate(this.getSignatures()); + containerValidator = new BDocContainerValidator(containerParseResult, getConfiguration(), !dataFilesHaveChanged); } else if (DocumentType.ASICS.name().equalsIgnoreCase(this.containerType)) { - return new AsicSContainerValidator(this.containerParseResult, this.getConfiguration(), - !this.dataFilesHaveChanged).validate(this.getSignatures()); + containerValidator = new AsicSContainerValidator(containerParseResult, getConfiguration(), !dataFilesHaveChanged); } else { - return new AsicEContainerValidator(this.containerParseResult, this.getConfiguration(), - !this.dataFilesHaveChanged).validate(this.getSignatures()); + containerValidator = new AsicEContainerValidator(containerParseResult, getConfiguration(), !dataFilesHaveChanged); } } else { if (DocumentType.BDOC.name().equalsIgnoreCase(this.containerType)) { - return new BDocContainerValidator(this.getConfiguration()).validate(this.getSignatures()); + containerValidator = new BDocContainerValidator(getConfiguration()); } else if (DocumentType.ASICS.name().equalsIgnoreCase(this.containerType)) { - return new AsicSContainerValidator(this.getConfiguration()).validate(this.getSignatures()); + containerValidator = new AsicSContainerValidator(getConfiguration()); } else { - return new AsicEContainerValidator(this.getConfiguration()).validate(this.getSignatures()); + containerValidator = new AsicEContainerValidator(getConfiguration()); } } + containerValidationResult = containerValidator.validate(getSignatures()); } + validateDataFiles(containerValidationResult); + return containerValidationResult; } private ContainerValidationResult validateTimestampToken() { @@ -199,6 +206,31 @@ private ContainerValidationResult validateTimestampToken() { return new TimeStampTokenValidator(this.containerParseResult).validate(); } + private void validateDataFiles(ContainerValidationResult containerValidationResult) { + List dataFilesValidationWarnings = dataFiles.stream() + .filter(DataFile::isFileEmpty) + .map(dataFile -> String.format("Data file '%s' is empty", dataFile.getName())) + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(dataFilesValidationWarnings)) { + return; + } + + if (containerValidationResult instanceof AbstractContainerValidationResult) { + AbstractContainerValidationResult abstractContainerValidationResult = (AbstractContainerValidationResult) containerValidationResult; + List exceptions = dataFilesValidationWarnings.stream().map(InvalidDataFileException::new).collect(Collectors.toList()); + abstractContainerValidationResult.addContainerWarnings(exceptions); + abstractContainerValidationResult.addWarnings(exceptions); + } else if (containerValidationResult instanceof AbstractValidationResult) { + List exceptions = dataFilesValidationWarnings.stream().map(InvalidDataFileException::new).collect(Collectors.toList()); + ((AbstractValidationResult) containerValidationResult).addWarnings(exceptions); + } else { + for (String dataFileValidationWarning : dataFilesValidationWarnings) { + LOGGER.warn(dataFileValidationWarning); + } + } + } + @Override public File saveAsFile(String filePath) { LOGGER.debug("Saving container to file: " + filePath); @@ -285,6 +317,14 @@ protected void validateDataFilesRemoval() { } } + protected void verifyDataFileIsNotEmpty(DataFile dataFile) { + if (dataFile.isFileEmpty()) { + String errorMessage = "Datafiles cannot be empty"; + LOGGER.error(errorMessage); + throw new InvalidDataFileException(errorMessage); + } + } + protected void verifyIfAllowedToAddDataFile(String fileName) { if (isContainerSigned()) { String errorMessage = "Datafiles cannot be added to an already signed container"; @@ -406,6 +446,7 @@ public DataFile addDataFile(File file, String mimeType) { @Override public void addDataFile(DataFile dataFile) { + verifyDataFileIsNotEmpty(dataFile); String fileName = dataFile.getName(); verifyIfAllowedToAddDataFile(fileName); if (Constant.ASICS_CONTAINER_TYPE.equals(getType())) { @@ -490,6 +531,10 @@ public void removeSignature(Signature signature) { } LOGGER.info("Removing signature " + signature.getId()); + if (!signatures.contains(signature)) { + throw new SignatureNotFoundException("Signature not found: " + signature.getId()); + } + if (!isNewContainer()) { validateIncomingSignature(signature); boolean wasNewlyAddedSignature = newSignatures.remove(signature); @@ -508,10 +553,13 @@ public void removeSignature(Signature signature) { @Deprecated public void removeSignature(int signatureId) { LOGGER.debug("Removing signature from index " + signatureId); - Signature signature = signatures.get(signatureId); - if (signature != null) { - removeSignature(signature); + if (signatureId >= 0 && signatureId < signatures.size()) { + Signature signature = signatures.get(signatureId); + if (signature != null) { + removeSignature(signature); + } } + throw new SignatureNotFoundException(String.format("Signature from index %d not found", signatureId)); } @Override @@ -522,6 +570,10 @@ public void removeDataFile(String fileName) { String name = dataFile.getName(); if (StringUtils.equals(fileName, name)) { removeDataFileFromContainer(dataFile); + dataFilesHaveChanged = true; + if (!isNewContainer()) { + removeExistingFileFromContainer(AsicManifest.XML_PATH); + } LOGGER.info("Data file named '{}' has been removed", fileName); return; } @@ -537,6 +589,10 @@ public void removeDataFile(DataFile file) { if (!wasRemovalSuccessful) { throw new DataFileNotFoundException(file.getName()); } + dataFilesHaveChanged = true; + if (!isNewContainer()) { + removeExistingFileFromContainer(AsicManifest.XML_PATH); + } LOGGER.info("Data file named '{}' has been removed", file.getName()); } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerCreator.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerCreator.java index c251d78a1..1bdc89173 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerCreator.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerCreator.java @@ -23,6 +23,7 @@ import java.util.zip.ZipOutputStream; import org.apache.commons.io.IOUtils; +import org.digidoc4j.Configuration; import org.digidoc4j.Constant; import org.digidoc4j.DataFile; import org.digidoc4j.Signature; @@ -49,11 +50,14 @@ public class AsicContainerCreator { private final ZipOutputStream zipOutputStream; private final OutputStream outputStream; private String zipComment; + private Configuration configuration; /** * @param outputStream stream + * @param configuration */ - public AsicContainerCreator(OutputStream outputStream) { + public AsicContainerCreator(OutputStream outputStream, Configuration configuration) { + this.configuration = configuration; this.outputStream = outputStream; this.zipOutputStream = new ZipOutputStream(outputStream, CHARSET); } @@ -65,7 +69,7 @@ public void finalizeZipFile() { } catch (IOException e) { handleIOException("Unable to finish creating asic ZIP container", e); } finally { - Helper.deleteTmpFiles(); + Helper.deleteTmpFiles(configuration.getTempFileMaxAge()); } } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerParser.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerParser.java index 0593a7038..93a7b106f 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerParser.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerParser.java @@ -1,16 +1,17 @@ /* DigiDoc4J library -* -* This software is released under either the GNU Library General Public -* License (see LICENSE.LGPL). -* -* Note that the only valid version of the LGPL license as far as this -* project is concerned is the original GNU Library General Public License -* Version 2.1, February 1999 -*/ + * + * This software is released under either the GNU Library General Public + * License (see LICENSE.LGPL). + * + * Note that the only valid version of the LGPL license as far as this + * project is concerned is the original GNU Library General Public License + * Version 2.1, February 1999 + */ package org.digidoc4j.impl.asic; import eu.europa.esig.dss.model.DSSDocument; +import eu.europa.esig.dss.model.DSSException; import eu.europa.esig.dss.model.InMemoryDocument; import eu.europa.esig.dss.model.MimeType; import org.apache.commons.io.IOUtils; @@ -72,6 +73,12 @@ public abstract class AsicContainerParser { private boolean mimeTypeFound = false; private long maxDataFileCachedInBytes; private DataFile timestampToken; + protected static final long ZIP_ENTRY_THRESHOLD = 1000000; // 1 MB + /** + * Maximum compression ratio. + */ + protected static final long ZIP_ENTRY_RATIO = 50; + protected AsicContainerParser(Configuration configuration) { this.configuration = configuration; @@ -81,6 +88,7 @@ protected AsicContainerParser(Configuration configuration) { /** * Method for parsing and validating ASiC container. + * * @return parsing result */ public AsicParseResult read() { @@ -173,12 +181,21 @@ private DSSDocument extractStreamDocument(ZipEntry entry) { logger.debug("Zip entry size is <{}> bytes", entry.getSize()); MimeType mimeTypeCode = MimeTypeUtil.mimeTypeOf(this.getDataFileMimeType(entry.getName())); if (this.storeDataFilesOnlyInMemory || entry.getSize() <= this.maxDataFileCachedInBytes) { - return new InMemoryDocument(this.getZipEntryInputStream(entry), entry.getName(), mimeTypeCode); + return new InMemoryDocument(toByteArray(this.getZipEntryInputStream(entry)), entry.getName(), mimeTypeCode); } else { return new StreamDocument(this.getZipEntryInputStream(entry), entry.getName(), mimeTypeCode); } } + private byte[] toByteArray(InputStream inputStream) { + try { + return IOUtils.toByteArray(inputStream); + } catch (IOException e) { + logger.error(e.getMessage()); + throw new TechnicalException(e.getMessage()); + } + } + protected AsicEntry extractAsicEntry(ZipEntry entry) { logger.debug("Extracting asic entry"); DSSDocument document = extractStreamDocument(entry); @@ -217,10 +234,10 @@ protected String getDataFileMimeType(String fileName) { private void validateParseResult() { if (!StringUtils.equalsIgnoreCase(MimeType.ASICE.getMimeTypeString(), mimeType) - && !StringUtils.equalsIgnoreCase(MimeType.ASICS.getMimeTypeString(), mimeType)) { + && !StringUtils.equalsIgnoreCase(MimeType.ASICS.getMimeTypeString(), mimeType)) { logger.error("Container mime type is not " + MimeType.ASICE.getMimeTypeString() + " but is " + mimeType); throw new UnsupportedFormatException("Container mime type is not " + MimeType.ASICE.getMimeTypeString() - + " OR " + MimeType.ASICS.getMimeTypeString() + " but is " + mimeType); + + " OR " + MimeType.ASICS.getMimeTypeString() + " but is " + mimeType); } if (!this.signatures.isEmpty() && this.dataFiles.isEmpty()) { throw new ContainerWithoutFilesException("The reference data object(s) is not found!"); diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerValidationResult.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerValidationResult.java index e48153b2b..628b7b8da 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerValidationResult.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicContainerValidationResult.java @@ -10,32 +10,26 @@ package org.digidoc4j.impl.asic; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - +import eu.europa.esig.dss.enumerations.Indication; +import eu.europa.esig.dss.enumerations.SignatureQualification; +import eu.europa.esig.dss.enumerations.SubIndication; +import eu.europa.esig.dss.simplereport.SimpleReport; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.digidoc4j.ContainerValidationResult; -import org.digidoc4j.exceptions.DigiDoc4JException; -import org.digidoc4j.impl.AbstractSignatureValidationResult; +import org.digidoc4j.impl.AbstractContainerValidationResult; -import eu.europa.esig.dss.enumerations.SignatureQualification; -import eu.europa.esig.dss.enumerations.Indication; -import eu.europa.esig.dss.enumerations.SubIndication; -import eu.europa.esig.dss.simplereport.SimpleReport; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Map; /** * Validation result information. *

    * For BDOC the ValidationResult contains only information for the first signature of each signature XML file */ -public class AsicContainerValidationResult extends AbstractSignatureValidationResult implements - ContainerValidationResult { +public class AsicContainerValidationResult extends AbstractContainerValidationResult implements ContainerValidationResult { - private List containerErrors = new ArrayList<>(); private Map signatureIdMap = Collections.emptyMap(); private AsicValidationReportBuilder validationReportBuilder; @@ -137,22 +131,4 @@ private String resolveSignatureId(String signatureId) { return signatureIdMap.getOrDefault(signatureId, signatureId); } - /* - * ACCESSORS - */ - - @Override - public List getContainerErrors() { - return containerErrors; - } - - /** - * Set container errors only. - * - * @param containerErrors Discovered list of container errors - */ - public void setContainerErrors(List containerErrors) { - this.containerErrors = containerErrors; - } - } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicFileContainerParser.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicFileContainerParser.java index 0e2c1070f..4caa8a321 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicFileContainerParser.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicFileContainerParser.java @@ -1,28 +1,29 @@ /* DigiDoc4J library -* -* This software is released under either the GNU Library General Public -* License (see LICENSE.LGPL). -* -* Note that the only valid version of the LGPL license as far as this -* project is concerned is the original GNU Library General Public License -* Version 2.1, February 1999 -*/ + * + * This software is released under either the GNU Library General Public + * License (see LICENSE.LGPL). + * + * Note that the only valid version of the LGPL license as far as this + * project is concerned is the original GNU Library General Public License + * Version 2.1, February 1999 + */ package org.digidoc4j.impl.asic; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - +import eu.europa.esig.dss.model.FileDocument; +import eu.europa.esig.dss.model.InMemoryDocument; +import eu.europa.esig.dss.spi.DSSUtils; import org.apache.commons.io.IOUtils; import org.digidoc4j.Configuration; import org.digidoc4j.exceptions.TechnicalException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import eu.europa.esig.dss.model.InMemoryDocument; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; /** * ASIC file container parser @@ -31,6 +32,7 @@ public class AsicFileContainerParser extends AsicContainerParser { private static final Logger logger = LoggerFactory.getLogger(AsicFileContainerParser.class); private ZipFile zipFile; + private long containerSize; /** * @param containerPath path @@ -39,6 +41,7 @@ public class AsicFileContainerParser extends AsicContainerParser { public AsicFileContainerParser(String containerPath, Configuration configuration) { super(configuration); try { + this.containerSize = DSSUtils.getFileByteSize(new FileDocument(containerPath)); zipFile = new ZipFile(containerPath); } catch (IOException e) { logger.error("Error reading container from " + containerPath + " - " + e.getMessage()); @@ -56,13 +59,29 @@ protected void parseContainer() { Enumeration entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry zipEntry = entries.nextElement(); + verifyIfZipBomb(getZipEntryInputStream(zipEntry)); parseEntry(zipEntry); } + } catch (IOException e) { + throw new TechnicalException("Zip Bomb detected in the ZIP container. Validation is interrupted."); } finally { IOUtils.closeQuietly(zipFile); } } + private void verifyIfZipBomb(InputStream inputStream) throws IOException { + byte[] data = new byte[2048]; + int nRead; + int byteCounter = 0; + long allowedSize = containerSize * ZIP_ENTRY_RATIO; + while ((nRead = inputStream.read(data)) != -1) { + byteCounter += nRead; + if (byteCounter > ZIP_ENTRY_THRESHOLD && byteCounter > allowedSize) { + throw new TechnicalException("Zip Bomb detected in the ZIP container. Validation is interrupted."); + } + } + } + @Override protected void extractManifest(ZipEntry entry) { extractAsicEntry(entry); diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicSignature.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicSignature.java index 3aa5d7cab..17282481c 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicSignature.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicSignature.java @@ -199,8 +199,8 @@ public ValidationResult validateSignature() { logger.info( "Signature has " + validationResult.getErrors().size() + " validation errors and " + validationResult.getWarnings().size() + " warnings"); } else { - logger.debug( - "Using existing validation errors with " + validationResult.getErrors().size() + " validation errors and " + validationResult.getWarnings().size() + " warnings"); + logger.debug("Using cached signature validation result. " + + "Signature has " + validationResult.getErrors().size() + " validation errors and " + validationResult.getWarnings().size() + " warnings"); } return validationResult; } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicStreamContainerParser.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicStreamContainerParser.java index 20054f796..36550d159 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicStreamContainerParser.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/AsicStreamContainerParser.java @@ -1,21 +1,17 @@ /* DigiDoc4J library -* -* This software is released under either the GNU Library General Public -* License (see LICENSE.LGPL). -* -* Note that the only valid version of the LGPL license as far as this -* project is concerned is the original GNU Library General Public License -* Version 2.1, February 1999 -*/ + * + * This software is released under either the GNU Library General Public + * License (see LICENSE.LGPL). + * + * Note that the only valid version of the LGPL license as far as this + * project is concerned is the original GNU Library General Public License + * Version 2.1, February 1999 + */ package org.digidoc4j.impl.asic; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.CountingInputStream; import org.digidoc4j.Configuration; import org.digidoc4j.DataFile; import org.digidoc4j.exceptions.TechnicalException; @@ -24,6 +20,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + /** * ASIC container parser from input stream */ @@ -31,14 +32,18 @@ public class AsicStreamContainerParser extends AsicContainerParser { private static final Logger logger = LoggerFactory.getLogger(AsicStreamContainerParser.class); private ZipInputStream zipInputStream; + private long entryOffset; + private static final int BUFFER_SIZE = 512; + CountingInputStream countingInputStream; /** - * @param inputStream input stream + * @param inputStream input stream * @param configuration configuration */ public AsicStreamContainerParser(InputStream inputStream, Configuration configuration) { super(configuration); - zipInputStream = new ZipInputStream(inputStream); + this.countingInputStream = new CountingInputStream(inputStream); + zipInputStream = new ZipInputStream(this.countingInputStream); } @Override @@ -51,9 +56,11 @@ private void parseZipStream() { logger.debug("Parsing zip stream"); try { ZipEntry entry; - while ((entry = zipInputStream.getNextEntry()) != null) { - parseEntry(entry); - } + + while ((entry = zipInputStream.getNextEntry()) != null) { + this.entryOffset = this.countingInputStream.getByteCount(); + parseEntry(entry); + } } catch (IOException e) { logger.error("Error reading asic container stream: " + e.getMessage()); throw new TechnicalException("Error reading asic container stream: ", e); @@ -78,6 +85,19 @@ protected void extractManifest(ZipEntry entry) { @Override protected InputStream getZipEntryInputStream(ZipEntry entry) { - return new ZipEntryInputStream(zipInputStream); + return new ZipEntryInputStream(zipInputStream, new EntryValidator()::validate); } + + protected class EntryValidator { + public void validate(long unCompressed) throws IOException { + long compressed = countingInputStream.getByteCount() - entryOffset; + if (compressed < BUFFER_SIZE) { + compressed = BUFFER_SIZE; + } + if (unCompressed > ZIP_ENTRY_THRESHOLD && compressed * ZIP_ENTRY_RATIO < unCompressed) { + throw new IOException("Zip Bomb detected in the ZIP container. Validation is interrupted."); + } + } + } + } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/DataLoaderDecorator.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/DataLoaderDecorator.java index 8312d022b..ec62d9740 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/DataLoaderDecorator.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/DataLoaderDecorator.java @@ -10,16 +10,17 @@ package org.digidoc4j.impl.asic; -import eu.europa.esig.dss.model.InMemoryDocument; import eu.europa.esig.dss.service.http.commons.CommonsDataLoader; import eu.europa.esig.dss.service.http.proxy.ProxyConfig; import eu.europa.esig.dss.service.http.proxy.ProxyProperties; import org.digidoc4j.Configuration; import org.digidoc4j.ExternalConnectionType; -import org.digidoc4j.utils.ResourceUtils; +import org.digidoc4j.utils.KeyStoreDocument; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.Duration; +import java.time.Period; import java.util.List; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -30,6 +31,20 @@ public class DataLoaderDecorator { private final static Logger logger = LoggerFactory.getLogger(DataLoaderDecorator.class); + /** + * Minimum validation interval of 5 minutes should be enough for the most common case of TSL data loaders, targeting + * key-store validation per each TSL cache update. + * Every time the TSL cache is updated (e.g. once a day), TLS trust-stores and/or key-stores are accessed (if configured) + * per TL fetch from each country. Minimum key-store validation interval should be long enough that the validation of the + * key-store is not performed multiple times per update cycle, but short enough the validation would be invoked per + * desired number of TSL updates. + */ + private final static Duration MIN_KEYSTORE_VALIDATION_INTERVAL = Duration.ofMinutes(5L); + /** + * Maximum warning period determines how long before certificate expiration date should warning messages about the upcoming + * expiration be logged. + */ + private final static Period MAX_KEYSTORE_WARNING_PERIOD = Period.ofDays(60); /** * @param dataLoader data loader @@ -37,15 +52,15 @@ public class DataLoaderDecorator { */ public static void decorateWithProxySettings(CommonsDataLoader dataLoader, Configuration configuration) { if (configuration.isNetworkProxyEnabled()) { - ProxyProperties httpProxyProperties = createProxyProperties( + ProxyProperties httpProxyProperties = createProxyPropertiesIfHostAndPortPresent( configuration.getHttpProxyPort(), configuration.getHttpProxyHost(), configuration.getHttpProxyUser(), configuration.getHttpProxyPassword() ); - ProxyProperties httpsProxyProperties = createProxyProperties( + ProxyProperties httpsProxyProperties = createProxyPropertiesIfHostAndPortPresent( configuration.getHttpsProxyPort(), configuration.getHttpsProxyHost(), configuration.getHttpProxyUser(), configuration.getHttpProxyPassword() ); - ProxyConfig proxyConfig = createProxyConfig(httpProxyProperties, httpsProxyProperties); + ProxyConfig proxyConfig = createProxyConfigIfAnyPropertiesPresent(httpProxyProperties, httpsProxyProperties); dataLoader.setProxyConfig(proxyConfig); } } @@ -57,38 +72,44 @@ public static void decorateWithProxySettings(CommonsDataLoader dataLoader, Confi */ public static void decorateWithProxySettingsFor(ExternalConnectionType connectionType, CommonsDataLoader dataLoader, Configuration configuration) { if (configuration.isNetworkProxyEnabledFor(connectionType)) { - ProxyProperties httpProxyProperties = createProxyProperties( + ProxyProperties httpProxyProperties = createProxyPropertiesIfHostAndPortPresent( configuration.getHttpProxyPortFor(connectionType), configuration.getHttpProxyHostFor(connectionType), configuration.getHttpProxyUserFor(connectionType), configuration.getHttpProxyPasswordFor(connectionType) ); - ProxyProperties httpsProxyProperties = createProxyProperties( + ProxyProperties httpsProxyProperties = createProxyPropertiesIfHostAndPortPresent( configuration.getHttpsProxyPortFor(connectionType), configuration.getHttpsProxyHostFor(connectionType), configuration.getHttpProxyUserFor(connectionType), configuration.getHttpProxyPasswordFor(connectionType) ); - ProxyConfig proxyConfig = createProxyConfig(httpProxyProperties, httpsProxyProperties); + ProxyConfig proxyConfig = createProxyConfigIfAnyPropertiesPresent(httpProxyProperties, httpsProxyProperties); dataLoader.setProxyConfig(proxyConfig); } } - private static ProxyConfig createProxyConfig(ProxyProperties httpProxyProperties, ProxyProperties httpsProxyProperties) { - logger.debug("Creating proxy settings"); - ProxyConfig proxyConfig = new ProxyConfig(); - proxyConfig.setHttpProperties(httpProxyProperties); - proxyConfig.setHttpsProperties(httpsProxyProperties); - return proxyConfig; + private static ProxyConfig createProxyConfigIfAnyPropertiesPresent(ProxyProperties httpProxyProperties, ProxyProperties httpsProxyProperties) { + if (httpProxyProperties != null || httpsProxyProperties != null) { + logger.debug("Creating proxy settings"); + ProxyConfig proxyConfig = new ProxyConfig(); + proxyConfig.setHttpProperties(httpProxyProperties); + proxyConfig.setHttpsProperties(httpsProxyProperties); + return proxyConfig; + } else { + return null; + } } - private static ProxyProperties createProxyProperties(Integer proxyPort, String proxyHost, String proxyUser, String proxyPassword) { - ProxyProperties proxyProperties = new ProxyProperties(); + private static ProxyProperties createProxyPropertiesIfHostAndPortPresent(Integer proxyPort, String proxyHost, String proxyUser, String proxyPassword) { if (proxyPort != null && isNotBlank(proxyHost)) { + ProxyProperties proxyProperties = new ProxyProperties(); proxyProperties.setPort(proxyPort); proxyProperties.setHost(proxyHost); + if (isNotBlank(proxyUser) && isNotBlank(proxyPassword)) { + proxyProperties.setUser(proxyUser); + proxyProperties.setPassword(proxyPassword); + } + return proxyProperties; + } else { + return null; } - if (isNotBlank(proxyUser) && isNotBlank(proxyPassword)) { - proxyProperties.setUser(proxyUser); - proxyProperties.setPassword(proxyPassword); - } - return proxyProperties; } /** @@ -128,7 +149,7 @@ public static void decorateWithSslSettingsFor(ExternalConnectionType connectionT private static void configureSslKeystore(CommonsDataLoader dataLoader, String sslKeystorePath, String sslKeystoreType, String sslKeystorePassword) { if (sslKeystorePath != null) { - dataLoader.setSslKeystore(new InMemoryDocument(ResourceUtils.getResource(sslKeystorePath))); + dataLoader.setSslKeystore(new KeyStoreDocument(sslKeystorePath, sslKeystoreType, sslKeystorePassword, MIN_KEYSTORE_VALIDATION_INTERVAL, MAX_KEYSTORE_WARNING_PERIOD)); if (sslKeystoreType != null) { dataLoader.setSslKeystoreType(sslKeystoreType); } @@ -140,7 +161,7 @@ private static void configureSslKeystore(CommonsDataLoader dataLoader, String ss private static void configureSslTruststore(CommonsDataLoader dataLoader, String sslTruststorePath, String sslTruststoreType, String sslTruststorePassword) { if (sslTruststorePath != null) { - dataLoader.setSslTruststore(new InMemoryDocument(ResourceUtils.getResource(sslTruststorePath))); + dataLoader.setSslTruststore(new KeyStoreDocument(sslTruststorePath, sslTruststoreType, sslTruststorePassword, MIN_KEYSTORE_VALIDATION_INTERVAL, MAX_KEYSTORE_WARNING_PERIOD)); if (sslTruststoreType != null) { dataLoader.setSslTruststoreType(sslTruststoreType); } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/TimeStampContainerValidationResult.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/TimeStampContainerValidationResult.java index 3c51709eb..12b312e42 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/TimeStampContainerValidationResult.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/TimeStampContainerValidationResult.java @@ -1,19 +1,14 @@ package org.digidoc4j.impl.asic; -import java.util.List; - +import eu.europa.esig.dss.enumerations.Indication; import org.bouncycastle.tsp.TimeStampToken; import org.digidoc4j.ContainerValidationResult; -import org.digidoc4j.exceptions.DigiDoc4JException; -import org.digidoc4j.impl.AbstractSignatureValidationResult; - -import eu.europa.esig.dss.enumerations.Indication; +import org.digidoc4j.impl.AbstractContainerValidationResult; /** * Created by Andrei on 27.11.2017. */ -public class TimeStampContainerValidationResult extends AbstractSignatureValidationResult implements - ContainerValidationResult { +public class TimeStampContainerValidationResult extends AbstractContainerValidationResult implements ContainerValidationResult { private TimeStampToken timeStampToken; private String signedBy = ""; @@ -31,11 +26,6 @@ public Indication getIndication() { return Indication.TOTAL_FAILED; } - @Override - public List getContainerErrors() { - return this.errors; - } - /* * RESTRICTED METHODS */ diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asice/AsicEContainer.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asice/AsicEContainer.java index 89e2ec1d0..532ec29f8 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asice/AsicEContainer.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asice/AsicEContainer.java @@ -157,7 +157,7 @@ protected AsicEContainer(AsicParseResult containerParseResult, Configuration con @Override public void save(OutputStream out) { - writeAsicContainer(new AsicContainerCreator(out)); + writeAsicContainer(new AsicContainerCreator(out, getConfiguration())); } @Override diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asics/AsicSContainer.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asics/AsicSContainer.java index a27ddf87f..55b771cdc 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asics/AsicSContainer.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/asics/AsicSContainer.java @@ -93,7 +93,7 @@ public DataFile getTimeStampToken() { @Override public void save(OutputStream out) { - writeAsicContainer(new AsicContainerCreator(out)); + writeAsicContainer(new AsicContainerCreator(out, getConfiguration())); } @Override diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/manifest/ManifestValidator.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/manifest/ManifestValidator.java index 0048f401d..667a665ed 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/manifest/ManifestValidator.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/manifest/ManifestValidator.java @@ -216,25 +216,11 @@ private String getFileURI(Reference reference) { private List getFilesInContainer() { List fileEntries = new ArrayList<>(); - - List signatureFileNames = getSignatureFileNames(); - for (DSSDocument detachedContent : detachedContents) { String name = detachedContent.getName(); - if (!(MANIFEST_PATH.equals(name) || ("META-INF/".equals(name)) || (MIMETYPE_PATH.equals(name) - || signatureFileNames.contains(name)))) { - fileEntries.add(name); - } + fileEntries.add(name); } return fileEntries; } - private List getSignatureFileNames() { - List signatureFileNames = new ArrayList<>(); - for (Signature signature : signatures) { - String signatureFileName = "META-INF/signature" + signature.getId().toLowerCase() + ".xml"; - signatureFileNames.add(signatureFileName); - } - return signatureFileNames; - } } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/tsl/TSLCertificateSourceImpl.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/tsl/TSLCertificateSourceImpl.java index 78bbfa3d1..f3ee6a7ba 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/tsl/TSLCertificateSourceImpl.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/tsl/TSLCertificateSourceImpl.java @@ -163,7 +163,7 @@ private String getCN(X509Certificate certificate) { private String getServiceType(X509Certificate certificate) { try { List extendedKeyUsage = certificate.getExtendedKeyUsage(); - if (extendedKeyUsage != null) { + if (extendedKeyUsage != null && certificate.getBasicConstraints() == -1) { if (extendedKeyUsage.contains(SKOnlineOCSPSource.OID_OCSP_SIGNING)) { return "http://uri.etsi.org/TrstSvc/Svctype/Certstatus/OCSP/QC"; } diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/xades/TimemarkSignature.java b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/xades/TimemarkSignature.java index dc58e4727..1da4442c7 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/asic/xades/TimemarkSignature.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/asic/xades/TimemarkSignature.java @@ -10,8 +10,10 @@ package org.digidoc4j.impl.asic.xades; +import eu.europa.esig.dss.model.DSSException; import eu.europa.esig.dss.model.x509.CertificateToken; import eu.europa.esig.dss.spi.DSSRevocationUtils; +import eu.europa.esig.dss.spi.DSSUtils; import org.apache.commons.lang3.StringUtils; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; @@ -21,9 +23,11 @@ import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.bouncycastle.cert.ocsp.BasicOCSPResp; import org.bouncycastle.cert.ocsp.RespID; +import org.bouncycastle.util.encoders.Hex; import org.digidoc4j.SignatureProfile; import org.digidoc4j.X509Cert; import org.digidoc4j.exceptions.CertificateNotFoundException; @@ -31,10 +35,14 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Signature for BDOC where timemark is taken from OCSP response. @@ -145,11 +153,10 @@ private BasicOCSPResp findOcspResponse() { } private X509Cert findOcspCertificate() { - String rId = ""; String signatureId = getDssSignature().getId(); + String responderIdString = ""; try { RespID responderId = ocspResponse.getResponderId(); - rId = responderId.toString(); String primitiveName = getCN(responderId.toASN1Primitive().getName()); byte[] keyHash = responderId.toASN1Primitive().getKeyHash(); @@ -157,11 +164,19 @@ private X509Cert findOcspCertificate() { if (isKeyHash) { logger.debug("Using keyHash {} for OCSP certificate match", keyHash); + responderIdString = Hex.toHexString(keyHash); } else { logger.debug("Using ASN1Primitive {} for OCSP certificate match", primitiveName); + responderIdString = primitiveName; } - for (CertificateToken cert : getDssSignature().getCertificates()) { + List availableCertificates = new ArrayList<>(); + Optional.ofNullable(ocspResponse.getCerts()).map(Arrays::stream).orElseGet(Stream::empty) + .map(TimemarkSignature::ocspCertificateHolderToCertificateToken).filter(Objects::nonNull) + .forEach(availableCertificates::add); + availableCertificates.addAll(getDssSignature().getCertificates()); + + for (CertificateToken cert : availableCertificates) { if (isKeyHash) { ASN1Primitive skiPrimitive = JcaX509ExtensionUtils.parseExtensionValue( cert.getCertificate().getExtensionValue(Extension.subjectKeyIdentifier.getId())); @@ -179,19 +194,31 @@ private X509Cert findOcspCertificate() { } } catch (IOException e) { - logger.error("Unable to wrap and extract SubjectKeyIdentifier from certificate - technical error. {}", e); + logger.error("Unable to wrap and extract SubjectKeyIdentifier from certificate - technical error.", e); } - logger.error("OCSP certificate for " + rId + " was not found in TSL"); - throw new CertificateNotFoundException("OCSP certificate for " + rId + " was not found in TSL", signatureId); + String errorMessage = String.format( + "OCSP certificate for \"%s\" was not found in neither OCSP response nor signature", + responderIdString + ); + logger.error(errorMessage); + throw new CertificateNotFoundException(errorMessage, signatureId); } - private boolean useKeyHashForOCSP(String primitiveName, byte[] keyHash) { + private static boolean useKeyHashForOCSP(String primitiveName, byte[] keyHash) { return (keyHash != null && keyHash.length > 0) && (primitiveName == null || primitiveName.trim().length() == 0); } + private static CertificateToken ocspCertificateHolderToCertificateToken(X509CertificateHolder x509CertificateHolder) { + try { + return DSSUtils.loadCertificate(x509CertificateHolder.getEncoded()); + } catch (DSSException | IOException e) { + logger.error("Failed to parse OCSP certificate: {}", getCN(x509CertificateHolder.getSubject()), e); + return null; + } + } - private String getCN(X500Name x500Name) { + private static String getCN(X500Name x500Name) { if (x500Name == null) return null; RDN[] rdNs = x500Name.getRDNs(new ASN1ObjectIdentifier("2.5.4.3")); if (rdNs == null || rdNs.length == 0) { diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocContainer.java b/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocContainer.java index 9bdde973a..25a826887 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocContainer.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocContainer.java @@ -100,7 +100,7 @@ public void removeDataFile(DataFile file) { @Override public void removeSignature(Signature signature) { - throw new NotSupportedException("Removing data files is not supported anymore for DDoc!"); + throw new NotSupportedException("Removing signatures is not supported anymore for DDoc!"); } @Override @@ -261,7 +261,7 @@ public void removeDataFile(String fileName) { @Override @Deprecated public void removeSignature(int signatureId) { - throw new NotSupportedException("Removing data files is not supported anymore for DDoc!"); + throw new NotSupportedException("Removing signatures is not supported anymore for DDoc!"); } /** diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocSignatureValidationResult.java b/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocSignatureValidationResult.java index 0289c5c7f..f7faf6bfc 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocSignatureValidationResult.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/ddoc/DDocSignatureValidationResult.java @@ -14,7 +14,7 @@ import org.digidoc4j.ddoc.DigiDocException; import org.digidoc4j.ddoc.SignedDoc; import org.digidoc4j.exceptions.DigiDoc4JException; -import org.digidoc4j.impl.AbstractSignatureValidationResult; +import org.digidoc4j.impl.AbstractContainerValidationResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Comment; @@ -33,11 +33,9 @@ /** * Overview of errors and warnings for DDoc */ -public class DDocSignatureValidationResult extends AbstractSignatureValidationResult implements - ContainerValidationResult { +public class DDocSignatureValidationResult extends AbstractContainerValidationResult implements ContainerValidationResult { private final Logger log = LoggerFactory.getLogger(DDocSignatureValidationResult.class); - private List containerExceptions = new ArrayList<>(); private Document document; private Element rootElement; private boolean hasFatalErrors = false; @@ -68,7 +66,7 @@ public DDocSignatureValidationResult(List exceptions, removeDuplicates(exceptions); removeDuplicates(openContainerExceptions); for (DigiDocException exception : openContainerExceptions) { - this.containerExceptions.add(new DigiDoc4JException(exception.getCode(), exception.getMessage())); + super.containerErrors.add(new DigiDoc4JException(exception.getCode(), exception.getMessage())); if (SignedDoc.hasFatalErrs((ArrayList) openContainerExceptions)) { this.hasFatalErrors = true; } @@ -166,11 +164,6 @@ private String toReportString(Document document) { * ACCESSORS */ - @Override - public List getContainerErrors() { - return containerExceptions; - } - /** * Does the container have fatal errors * diff --git a/digidoc4j/src/main/java/org/digidoc4j/impl/pades/PadesContainerValidationResult.java b/digidoc4j/src/main/java/org/digidoc4j/impl/pades/PadesContainerValidationResult.java index 235f58e9c..dd1c3eaf7 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/impl/pades/PadesContainerValidationResult.java +++ b/digidoc4j/src/main/java/org/digidoc4j/impl/pades/PadesContainerValidationResult.java @@ -1,23 +1,19 @@ package org.digidoc4j.impl.pades; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - +import eu.europa.esig.dss.enumerations.Indication; +import eu.europa.esig.dss.enumerations.SubIndication; +import eu.europa.esig.dss.simplereport.SimpleReport; import org.apache.commons.lang3.StringUtils; import org.digidoc4j.ContainerValidationResult; import org.digidoc4j.exceptions.DigiDoc4JException; -import org.digidoc4j.impl.AbstractSignatureValidationResult; +import org.digidoc4j.impl.AbstractContainerValidationResult; -import eu.europa.esig.dss.enumerations.Indication; -import eu.europa.esig.dss.enumerations.SubIndication; -import eu.europa.esig.dss.simplereport.SimpleReport; +import java.util.Arrays; /** * Created by Andrei on 20.11.2017. */ -public class PadesContainerValidationResult extends AbstractSignatureValidationResult implements - ContainerValidationResult { +public class PadesContainerValidationResult extends AbstractContainerValidationResult implements ContainerValidationResult { /** * @param simpleReport simple report @@ -51,13 +47,4 @@ protected String getResultName() { return "PAdES container"; } - /* - * ACCESSORS - */ - - @Override - public List getContainerErrors() { - return Collections.emptyList(); - } - } diff --git a/digidoc4j/src/main/java/org/digidoc4j/signers/ExternalSigner.java b/digidoc4j/src/main/java/org/digidoc4j/signers/ExternalSigner.java index c3fd8067a..4946ad590 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/signers/ExternalSigner.java +++ b/digidoc4j/src/main/java/org/digidoc4j/signers/ExternalSigner.java @@ -35,4 +35,9 @@ public X509Certificate getCertificate() { return this.signingCertificate; } + @Override + public void close(){ + //Do nothing + } + } diff --git a/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS11SignatureToken.java b/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS11SignatureToken.java index 25ad374df..28d25f752 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS11SignatureToken.java +++ b/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS11SignatureToken.java @@ -49,7 +49,7 @@ * For Linux, it could be /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so,
    * For OSX, it could be /usr/local/lib/opensc-pkcs11.so
    */ -public class PKCS11SignatureToken implements SignatureToken { +public class PKCS11SignatureToken implements SignatureToken { private static final Logger logger = LoggerFactory.getLogger(PKCS11SignatureToken.class); private static final String EXTRA_PKCS11_CONFIG = ""; @@ -98,7 +98,7 @@ public PKCS11SignatureToken(String pkcs11ModulePath, PasswordInputCallback passw public PKCS11SignatureToken(String pkcs11ModulePath, char[] password, int slotIndex, String label) { this.label = label; logger.debug("Initializing PKCS#11 signature token from " + pkcs11ModulePath + " and slot " + slotIndex + " and " + - "label " + label); + "label " + label); PasswordInputCallback passwordCallback = new PrefilledPasswordCallback(new KeyStore.PasswordProtection(password)); signatureTokenConnection = new Pkcs11SignatureToken(pkcs11ModulePath, passwordCallback, DEFAULT_SLOT_ID, slotIndex, EXTRA_PKCS11_CONFIG); privateKeyEntry = findPrivateKey(X509Cert.KeyUsage.NON_REPUDIATION); @@ -119,7 +119,7 @@ public PKCS11SignatureToken(String pkcs11ModulePath, PasswordInputCallback passw String label) { this.label = label; logger.debug("Initializing PKCS#11 signature token with password callback from " + pkcs11ModulePath + " and " + - "slot " + slotIndex + " Label " + label); + "slot " + slotIndex + " Label " + label); signatureTokenConnection = new Pkcs11SignatureToken(pkcs11ModulePath, passwordCallback, DEFAULT_SLOT_ID, slotIndex, EXTRA_PKCS11_CONFIG); privateKeyEntry = findPrivateKey(X509Cert.KeyUsage.NON_REPUDIATION); } @@ -175,7 +175,7 @@ public byte[] sign(DigestAlgorithm digestAlgorithm, byte[] dataToSign) { return signRSA(digestAlgorithm, dataToSign); } throw new TechnicalException("Failed to sign with PKCS#11. Encryption Algorithm should be ECDSA or RSA " + - "but actually is : " + encryptionAlg); + "but actually is : " + encryptionAlg); } throw new TechnicalException("privateKeyEntry is null"); } @@ -228,4 +228,9 @@ private byte[] invokeSigning(byte[] digestToSign, PrivateKey privateKey, String byte[] signatureValue = signer.sign(); return signatureValue; } + + @Override + public void close() { + signatureTokenConnection.close(); + } } diff --git a/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS12SignatureToken.java b/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS12SignatureToken.java index c2d08ffc4..98af77ffa 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS12SignatureToken.java +++ b/digidoc4j/src/main/java/org/digidoc4j/signers/PKCS12SignatureToken.java @@ -1,12 +1,12 @@ /* DigiDoc4J library -* -* This software is released under either the GNU Library General Public -* License (see LICENSE.LGPL). -* -* Note that the only valid version of the LGPL license as far as this -* project is concerned is the original GNU Library General Public License -* Version 2.1, February 1999 -*/ + * + * This software is released under either the GNU Library General Public + * License (see LICENSE.LGPL). + * + * Note that the only valid version of the LGPL license as far as this + * project is concerned is the original GNU Library General Public License + * Version 2.1, February 1999 + */ package org.digidoc4j.signers; @@ -19,6 +19,7 @@ import org.digidoc4j.SignatureToken; import org.digidoc4j.X509Cert; import org.digidoc4j.exceptions.DigiDoc4JException; +import org.digidoc4j.exceptions.InvalidKeyException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,7 +61,7 @@ public PKCS12SignatureToken(String fileName, String password) { * * @param fileName .p12 file name and path * @param password keystore password as String - * @param alias known key alias + * @param alias known key alias */ public PKCS12SignatureToken(String fileName, String password, String alias) { init(fileName, password, X509Cert.KeyUsage.NON_REPUDIATION, alias); @@ -98,11 +99,12 @@ private void init(String fileName, String password, X509Cert.KeyUsage keyUsage, } } if (keyEntry == null && signatureTokenConnection.getKeys().size() > 0) - keyEntry = (KSPrivateKeyEntry)signatureTokenConnection.getKeys().get(0); + keyEntry = (KSPrivateKeyEntry) signatureTokenConnection.getKeys().get(0); } /** * Method for asking DSS signature token connection + * * @return DSS signature token connection */ public KeyStoreSignatureTokenConnection getSignatureTokenConnection() { @@ -111,20 +113,33 @@ public KeyStoreSignatureTokenConnection getSignatureTokenConnection() { @Override public X509Certificate getCertificate() { + if (keyEntry == null) { + throw new InvalidKeyException("Private key entry is missing. Connection may be closed."); + } logger.debug("Using key with alias: ", getAlias()); return keyEntry.getCertificate().getCertificate(); } @Override public byte[] sign(org.digidoc4j.DigestAlgorithm digestAlgorithm, byte[] dataToSign) { + logger.info("Signing with PKCS#12 signature token, using digest algorithm: " + digestAlgorithm.name()); ToBeSigned toBeSigned = new ToBeSigned(dataToSign); eu.europa.esig.dss.enumerations.DigestAlgorithm dssDigestAlgorithm = eu.europa.esig.dss.enumerations.DigestAlgorithm.forXML(digestAlgorithm.toString()); + if (keyEntry == null) { + throw new InvalidKeyException("Private key entry is missing. Connection may be closed."); + } SignatureValue signature = signatureTokenConnection.sign(toBeSigned, dssDigestAlgorithm, keyEntry); return signature.getValue(); } + @Override + public void close() { + signatureTokenConnection.close(); + keyEntry = null; + } + /** * Returns key entry alias in keyStore. */ diff --git a/digidoc4j/src/main/java/org/digidoc4j/utils/Helper.java b/digidoc4j/src/main/java/org/digidoc4j/utils/Helper.java index 162480d94..df1e23763 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/utils/Helper.java +++ b/digidoc4j/src/main/java/org/digidoc4j/utils/Helper.java @@ -1,12 +1,12 @@ /* DigiDoc4J library -* -* This software is released under either the GNU Library General Public -* License (see LICENSE.LGPL). -* -* Note that the only valid version of the LGPL license as far as this -* project is concerned is the original GNU Library General Public License -* Version 2.1, February 1999 -*/ + * + * This software is released under either the GNU Library General Public + * License (see LICENSE.LGPL). + * + * Note that the only valid version of the LGPL license as far as this + * project is concerned is the original GNU Library General Public License + * Version 2.1, February 1999 + */ package org.digidoc4j.utils; @@ -230,8 +230,8 @@ public static String extractSignature(String file, int index) throws IOException */ public static void serialize(T object, File file) { try ( - FileOutputStream fileOut = new FileOutputStream(file); - ObjectOutputStream out = new ObjectOutputStream(fileOut); + FileOutputStream fileOut = new FileOutputStream(file); + ObjectOutputStream out = new ObjectOutputStream(fileOut); ) { out.writeObject(object); out.flush(); @@ -259,8 +259,8 @@ public static void serialize(T object, String filename) { */ public static T deserializer(File file) { try ( - FileInputStream fileIn = new FileInputStream(file); - ObjectInputStream in = new ObjectInputStream(fileIn); + FileInputStream fileIn = new FileInputStream(file); + ObjectInputStream in = new ObjectInputStream(fileIn); ) { T object = (T) in.readObject(); return object; @@ -412,15 +412,14 @@ public static void saveAllFilesFromContainerPathToFolder(String pathFrom, String /** * delete tmp files from temp folder created by StreamDocument */ - public static void deleteTmpFiles() { + public static void deleteTmpFiles(long allowedAge) { File dir = new File(System.getProperty("java.io.tmpdir")); - FilenameFilter filenameFilter = new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.toLowerCase().startsWith("digidoc4j") && name.toLowerCase().endsWith(".tmp"); - } - }; + FilenameFilter filenameFilter = (dir1, name) -> name.toLowerCase().startsWith("digidoc4j") + && name.toLowerCase().endsWith(".tmp"); for (File f : dir.listFiles(filenameFilter)) { + if (System.currentTimeMillis() - f.lastModified() < allowedAge) { + continue; + } if (!f.delete()) { f.deleteOnExit(); } @@ -491,7 +490,7 @@ private static File[] getFilesFromJar(URL jarUrl, FileFilter filter) { } for (ZipEntry entry : entries) { try (InputStream inputStream = zipFile.getInputStream(entry); OutputStream outputStream = new - FileOutputStream(Paths.get(outputFolder.getPath(), new File(entry.getName()).getName()).toFile())) { + FileOutputStream(Paths.get(outputFolder.getPath(), new File(entry.getName()).getName()).toFile())) { IOUtils.copy(inputStream, outputStream); } } diff --git a/digidoc4j/src/main/java/org/digidoc4j/utils/KeyStoreDocument.java b/digidoc4j/src/main/java/org/digidoc4j/utils/KeyStoreDocument.java new file mode 100644 index 000000000..7fd871ab8 --- /dev/null +++ b/digidoc4j/src/main/java/org/digidoc4j/utils/KeyStoreDocument.java @@ -0,0 +1,168 @@ +package org.digidoc4j.utils; + +import eu.europa.esig.dss.model.CommonDocument; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.TemporalAmount; +import java.util.Enumeration; +import java.util.Objects; + +/** + * An implementation of {@link eu.europa.esig.dss.model.DSSDocument} for caching and serving key-stores and trust-stores + * for {@link eu.europa.esig.dss.service.http.commons.CommonsDataLoader}s. + * + * Invoking {@link #openStream()}, {@link #writeTo(OutputStream)} or {@link #save(String)} will trigger key-store content + * validation if at least {@code minValidationInterval} has passed since the last validation. + * For each certificate that has expired or will expire in {@code maxWarningPeriod}, a WARNING will be logged. + */ +public class KeyStoreDocument extends CommonDocument { + + private final static Logger logger = LoggerFactory.getLogger(KeyStoreDocument.class); + + private final String path; + private final String type; + private final char[] password; + private final Duration validationInterval; + private final TemporalAmount warningPeriod; + + private final byte[] rawKeyStoreBytes; + + private Instant lastValidated; + + /** + * Instantiates this instance of {@link KeyStoreDocument}. + * + * @param path path to key-store; see {@link ResourceUtils#getResource(String)} + * @param type key-store type; defaults to {@link KeyStore#getDefaultType()} if not provided + * @param password key-store password; can be {@code null} + * @param minValidationInterval minimum interval between key-store accesses that can trigger key-store validation + * @param maxWarningPeriod maximum time before a certificate expiry before logging warnings about the certificate starts + */ + public KeyStoreDocument(String path, String type, String password, Duration minValidationInterval, TemporalAmount maxWarningPeriod) { + this.path = Objects.requireNonNull(path, "Key-store path cannot be null"); + validationInterval = Objects.requireNonNull(minValidationInterval, "Validation interval cannot be null"); + warningPeriod = Objects.requireNonNull(maxWarningPeriod, "Warning period cannot be null"); + + this.type = (type != null) ? type : KeyStore.getDefaultType(); + this.password = (password != null) ? password.toCharArray() : null; + + rawKeyStoreBytes = loadRawKeyStoreBytes(path); + validateKeyStoreIfLastValidationExpired(); + } + + @Override + public InputStream openStream() { + validateKeyStoreIfLastValidationExpired(); + return new ByteArrayInputStream(rawKeyStoreBytes); + } + + @Override + public void writeTo(OutputStream stream) throws IOException { + validateKeyStoreIfLastValidationExpired(); + stream.write(rawKeyStoreBytes); + } + + private static byte[] loadRawKeyStoreBytes(String path) { + try (InputStream inputStream = ResourceUtils.getResource(path)) { + return IOUtils.toByteArray(inputStream); + } catch (IOException e) { + throw new IllegalStateException("Failed to load key-store from: " + path, e); + } + } + + private void validateKeyStoreIfLastValidationExpired() { + Instant now = Instant.now(); + + if (lastValidated != null) { + Duration difference = Duration.between(lastValidated, now); + if (difference.compareTo(validationInterval) < 0) { + return; + } + } + + KeyStore keyStore = loadKeyStoreFromRawBytes(); + Instant safeExpiryTime = now.plus(warningPeriod); + + try { + Enumeration aliases = keyStore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + Certificate[] certificates = getCertificatesByAlias(keyStore, alias); + for (Certificate certificate : certificates) { + validateCertificate(certificate, alias, now, safeExpiryTime); + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException("Failed to list key-store entries from key-store: " + path, e); + } + + lastValidated = now; + } + + private KeyStore loadKeyStoreFromRawBytes() { + KeyStore keyStore; + try { + keyStore = KeyStore.getInstance(type); + } catch (KeyStoreException e) { + throw new IllegalStateException("Failed to create key-store of type: " + type, e); + } + try (InputStream inputStream = new ByteArrayInputStream(rawKeyStoreBytes)) { + keyStore.load(inputStream, password); + } catch (CertificateException | IOException | NoSuchAlgorithmException e) { + throw new IllegalStateException("Failed to load key-store from: " + path, e); + } + return keyStore; + } + + private void validateCertificate(Certificate certificate, String alias, Instant currentTime, Instant safeExpiryTime) { + if (certificate instanceof X509Certificate) { + X509Certificate x509Certificate = (X509Certificate) certificate; + Instant timeOfExpiring = x509Certificate.getNotAfter().toInstant(); + if (timeOfExpiring.isBefore(currentTime)) { + logger.warn( + "Certificate from \"{}\" has already expired ({}) - alias: \"{}\"; subject: \"{}\"", + path, timeOfExpiring, alias, x509Certificate.getSubjectDN() + ); + } else if (timeOfExpiring.isBefore(safeExpiryTime)) { + long daysUntilExpiring = Duration.between(timeOfExpiring, safeExpiryTime).toDays(); + logger.warn( + "Certificate from \"{}\" expires ({}) in about {} day(s) - alias: \"{}\"; subject: \"{}\"", + path, timeOfExpiring, daysUntilExpiring, alias, x509Certificate.getSubjectDN() + ); + } + } else { + logger.warn( + "Certificate from \"{}\" is of unrecognized type: \"{}\"; alias: \"{}\"", + path, certificate.getClass().getCanonicalName(), alias + ); + } + } + + private static Certificate[] getCertificatesByAlias(KeyStore keyStore, String alias) throws KeyStoreException { + Certificate[] certificateChain = keyStore.getCertificateChain(alias); + if (ArrayUtils.isNotEmpty(certificateChain)) { + return certificateChain; + } + Certificate certificate = keyStore.getCertificate(alias); + if (certificate != null) { + return new Certificate[] {certificate}; + } + return new Certificate[0]; + } + +} diff --git a/digidoc4j/src/main/java/org/digidoc4j/utils/PolicyUtils.java b/digidoc4j/src/main/java/org/digidoc4j/utils/PolicyUtils.java index 956848e94..c03180c58 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/utils/PolicyUtils.java +++ b/digidoc4j/src/main/java/org/digidoc4j/utils/PolicyUtils.java @@ -28,7 +28,7 @@ public final class PolicyUtils { public static Policy createBDocSignaturePolicy() { Policy signaturePolicy = new Policy(); signaturePolicy.setId("urn:oid:" + XadesSignatureValidator.TM_POLICY); - signaturePolicy.setDigestValue(Base64.decodeBase64("7pudpH4eXlguSZY2e/pNbKzGsq+fu//woYL1SZFws1A=")); + signaturePolicy.setDigestValue(Base64.decodeBase64("3Tl1oILSvOAWomdI9VeWV6IA/32eSXRUri9kPEz1IVs=")); signaturePolicy.setQualifier(ObjectIdentifierQualifier.OID_AS_URN); signaturePolicy.setDigestAlgorithm(SHA256); signaturePolicy.setSpuri("https://www.sk.ee/repository/bdoc-spec21.pdf"); diff --git a/digidoc4j/src/main/java/org/digidoc4j/utils/ResourceUtils.java b/digidoc4j/src/main/java/org/digidoc4j/utils/ResourceUtils.java index 9889ad2bc..4c5b63d39 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/utils/ResourceUtils.java +++ b/digidoc4j/src/main/java/org/digidoc4j/utils/ResourceUtils.java @@ -14,6 +14,9 @@ public final class ResourceUtils { private static final Logger LOGGER = LoggerFactory.getLogger(ResourceUtils.class); + private static final String CLASSPATH_PREFIX = "classpath:"; + private static final String FILE_PREFIX = "file:"; + public static boolean isResourceAccessible(String path) { try { return ResourceUtils.class.getClassLoader().getResource(path) != null; @@ -34,15 +37,15 @@ public static boolean isFileReadable(String path) { } public static InputStream getResource(String path) { - if (path.startsWith("classpath:")) { - path = path.substring("classpath:".length()); + if (path.startsWith(CLASSPATH_PREFIX)) { + path = path.substring(CLASSPATH_PREFIX.length()); InputStream inputStream = ResourceUtils.class.getClassLoader().getResourceAsStream(path); if (inputStream == null) { throw new IllegalArgumentException("Resource not found: " + path); } return inputStream; - } else if (path.startsWith("file:")) { - path = path.substring("file:".length()); + } else if (path.startsWith(FILE_PREFIX)) { + path = path.substring(FILE_PREFIX.length()); } try { return new FileInputStream(path); diff --git a/digidoc4j/src/main/java/org/digidoc4j/utils/ZipEntryInputStream.java b/digidoc4j/src/main/java/org/digidoc4j/utils/ZipEntryInputStream.java index 59a609196..619b4e202 100644 --- a/digidoc4j/src/main/java/org/digidoc4j/utils/ZipEntryInputStream.java +++ b/digidoc4j/src/main/java/org/digidoc4j/utils/ZipEntryInputStream.java @@ -10,55 +10,76 @@ */ public class ZipEntryInputStream extends InputStream { - private final ZipInputStream zipInputStream; + private final ZipInputStream zipInputStream; + private final ThrowingConsumer validator; + private int counter; - public ZipEntryInputStream(ZipInputStream zipInputStream) { - this.zipInputStream = zipInputStream; - } + public ZipEntryInputStream(ZipInputStream zipInputStream, ThrowingConsumer validator) { + this.zipInputStream = zipInputStream; + this.validator = validator; + } - @Override - public int available() throws IOException { - return zipInputStream.available(); - } + @Override + public int available() throws IOException { + return zipInputStream.available(); + } - @Override - public void close() throws IOException { - zipInputStream.closeEntry(); - } + @Override + public void close() throws IOException { + zipInputStream.closeEntry(); + } - @Override - public void mark(int readlimit) { - zipInputStream.mark(readlimit); - } + @Override + public void mark(int readlimit) { + zipInputStream.mark(readlimit); + } - @Override - public boolean markSupported() { - return zipInputStream.markSupported(); - } + @Override + public boolean markSupported() { + return zipInputStream.markSupported(); + } - @Override - public int read() throws IOException { - return zipInputStream.read(); - } + @Override + public int read() throws IOException { + int result = zipInputStream.read(); + checkEntry(result); + return result; + } - @Override - public int read(byte[] b) throws IOException { - return zipInputStream.read(b); - } + @Override + public int read(byte[] b) throws IOException { + int result = zipInputStream.read(b); + checkEntry(result); + return result; + } - @Override - public int read(byte[] b, int off, int len) throws IOException { - return zipInputStream.read(b, off, len); - } + @Override + public int read(byte[] b, int off, int len) throws IOException { + int result = zipInputStream.read(b, off, len); + checkEntry(result); + return result; + } - @Override - public void reset() throws IOException { - zipInputStream.reset(); - } + @Override + public void reset() throws IOException { + zipInputStream.reset(); + } - @Override - public long skip(long n) throws IOException { - return zipInputStream.skip(n); + @Override + public long skip(long n) throws IOException { + return zipInputStream.skip(n); + } + + private void checkEntry(int result) throws IOException { + if (validator != null) { + counter += result; + validator.accept(counter); } + } + + @FunctionalInterface + public interface ThrowingConsumer { + void accept(T t) throws E; + } } diff --git a/digidoc4j/src/main/resources/conf/constraint.xml b/digidoc4j/src/main/resources/conf/constraint.xml index 161c62d29..35b969d53 100644 --- a/digidoc4j/src/main/resources/conf/constraint.xml +++ b/digidoc4j/src/main/resources/conf/constraint.xml @@ -15,24 +15,15 @@ - + - - - + + @@ -43,10 +34,6 @@ - - - - @@ -186,8 +173,6 @@ - - diff --git a/digidoc4j/src/main/resources/conf/test_constraint.xml b/digidoc4j/src/main/resources/conf/test_constraint.xml index 161c62d29..35b969d53 100644 --- a/digidoc4j/src/main/resources/conf/test_constraint.xml +++ b/digidoc4j/src/main/resources/conf/test_constraint.xml @@ -15,24 +15,15 @@ - + - - - + + @@ -43,10 +34,6 @@ - - - - @@ -186,8 +173,6 @@ - - diff --git a/digidoc4j/src/main/resources/ssl/tsl_truststore.p12 b/digidoc4j/src/main/resources/ssl/tsl_truststore.p12 index bcea473ab..57df1d700 100644 Binary files a/digidoc4j/src/main/resources/ssl/tsl_truststore.p12 and b/digidoc4j/src/main/resources/ssl/tsl_truststore.p12 differ diff --git a/digidoc4j/src/test/java/org/digidoc4j/AbstractTest.java b/digidoc4j/src/test/java/org/digidoc4j/AbstractTest.java index d71a39dbb..e3053cd2a 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/AbstractTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/AbstractTest.java @@ -82,7 +82,7 @@ public abstract class AbstractTest extends ConfigurationSingeltonHolder { protected static final String USER_AGENT_STRING = "test-user-agent"; - protected static final PKCS12SignatureToken pkcs12SignatureToken = new PKCS12SignatureToken("src/test/resources/testFiles/p12/signout.p12", "test".toCharArray()); + protected static final PKCS12SignatureToken pkcs12SignatureToken = new PKCS12SignatureToken("src/test/resources/testFiles/p12/sign_RSA_from_TEST_of_ESTEIDSK2015.p12", "1234".toCharArray()); protected static final PKCS12SignatureToken pkcs12EccSignatureToken = new PKCS12SignatureToken("src/test/resources/testFiles/p12/MadDogOY.p12", "test".toCharArray()); protected static final PKCS12SignatureToken pkcs12Esteid2018SignatureToken = new PKCS12SignatureToken("src/test/resources/testFiles/p12/sign_ESTEID2018.p12", "1234".toCharArray()); protected Configuration configuration; @@ -205,22 +205,27 @@ protected Container openContainerByConfiguration(Path path, Configuration config return builder.build(); } + @SuppressWarnings("unchecked") protected T createEmptyContainer() { return (T) ContainerBuilder.aContainer().build(); } + @SuppressWarnings("unchecked") protected T createEmptyContainer(Configuration configuration) { return (T) ContainerBuilder.aContainer().withConfiguration(configuration).build(); } + @SuppressWarnings("unchecked") protected T createEmptyContainer(Class clazz) { return (T) ContainerBuilder.aContainer().build(); } + @SuppressWarnings("unchecked") protected T createEmptyContainerBy(Container.DocumentType type) { return (T) ContainerBuilder.aContainer(type).build(); } + @SuppressWarnings("unchecked") protected T createEmptyContainerBy(Container.DocumentType type, Class clazz) { return (T) ContainerBuilder.aContainer(type).build(); } @@ -230,7 +235,7 @@ protected Container createNonEmptyContainer() { } protected Container createNonEmptyContainerByConfiguration() { - return ContainerBuilder.aContainer().withConfiguration(this.configuration) + return ContainerBuilder.aContainer(BDOC).withConfiguration(this.configuration) .withDataFile(this.createTemporaryFileBy("TOP SECRET").getPath(), "text/plain").build(); } @@ -287,7 +292,7 @@ protected File createTemporaryFileBy(String content) { protected String getFileContent(InputStream stream) { try { - return IOUtils.toString(stream, "UTF-8"); + return IOUtils.toString(stream, StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException(e); } @@ -309,6 +314,7 @@ protected String getFileBy(String extension, boolean create) { return file; } + @SuppressWarnings("unchecked") protected T createSignatureBy(Container container, SignatureToken signatureToken) { return (T) this.createSignatureBy(container, (SignatureProfile) null, signatureToken); } @@ -321,6 +327,7 @@ protected T createSignatureBy(Container container, SignatureProfile signatur return this.createSignatureBy(container, signatureProfile, null, signatureToken); } + @SuppressWarnings("unchecked") protected T createSignatureBy(Container container, SignatureProfile signatureProfile, DigestAlgorithm digestAlgorithm, SignatureToken signatureToken) { SignatureBuilder builder = SignatureBuilder.aSignature(container).withSignatureToken(signatureToken); if (signatureProfile != null) { @@ -335,21 +342,22 @@ protected T createSignatureBy(Container container, SignatureProfile signatur } protected T createSignatureBy(Container.DocumentType type, SignatureToken signatureToken) { - return (T) this.createSignatureBy(type, null, signatureToken, Configuration.Mode.TEST); + return this.createSignatureBy(type, null, signatureToken, Configuration.Mode.TEST); } protected T createSignatureBy(Container.DocumentType type, SignatureToken signatureToken, Class clazz) { - return (T) this.createSignatureBy(type, null, signatureToken, Configuration.Mode.TEST); + return this.createSignatureBy(type, null, signatureToken, Configuration.Mode.TEST); } protected T createSignatureBy(Container.DocumentType type, SignatureToken signatureToken, Configuration.Mode mode) { - return (T) this.createSignatureBy(type, null, signatureToken, mode); + return this.createSignatureBy(type, null, signatureToken, mode); } protected T createSignatureBy(Container.DocumentType type, SignatureProfile signatureProfile, SignatureToken signatureToken) { - return (T) this.createSignatureBy(type, signatureProfile, signatureToken, Configuration.Mode.TEST); + return this.createSignatureBy(type, signatureProfile, signatureToken, Configuration.Mode.TEST); } + @SuppressWarnings("unchecked") protected T createSignatureBy(Container.DocumentType type, SignatureProfile signatureProfile, SignatureToken signatureToken, Configuration.Mode mode) { try { SignatureBuilder builder = SignatureBuilder.aSignature(TestDataBuilderUtil.createContainerWithFile(this.testFolder, type, mode)); @@ -362,6 +370,7 @@ protected T createSignatureBy(Container.DocumentType type, SignatureProfile } } + @SuppressWarnings("unchecked") protected T createSignatureBy(DigestAlgorithm digestAlgorithm, SignatureToken signatureToken) { try { return (T) SignatureBuilder.aSignature(this.createNonEmptyContainer()).withSignatureDigestAlgorithm(digestAlgorithm). @@ -374,7 +383,7 @@ protected T createSignatureBy(DigestAlgorithm digestAlgorithm, SignatureToke protected String createSignedContainerBy(String extension) { String file = this.getFileBy(extension); Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); container.save(file); return file; } @@ -403,11 +412,11 @@ protected DSSDocument sign(XadesSigningDssFacade facade, DigestAlgorithm digestA } protected byte[] sign(byte[] dataToSign, DigestAlgorithm digestAlgorithm) { - return this.pkcs12SignatureToken.sign(digestAlgorithm, dataToSign); + return pkcs12SignatureToken.sign(digestAlgorithm, dataToSign); } protected byte[] getDataToSign(XadesSigningDssFacade facade) { - facade.setSigningCertificate(this.pkcs12SignatureToken.getCertificate()); + facade.setSigningCertificate(pkcs12SignatureToken.getCertificate()); return facade.getDataToSign(this.createDataFilesToSign()); } @@ -461,6 +470,25 @@ private OnlineTSPSource createTSPSource() { return source; } + @FunctionalInterface + protected interface PotentiallyThrowing { + void run() throws T; + } + + @SuppressWarnings("unchecked") + protected static T assertThrows(Class type, PotentiallyThrowing toTest) { + try { + toTest.run(); + } catch (Throwable t) { + if (type.isInstance(t)) { + return (T) t; + } + Assert.fail(String.format("Expected %s, but an %s was thrown: %s", type.getSimpleName(), t.getClass().getSimpleName(), t.getMessage())); + } + Assert.fail(String.format("Expected %s, but nothing was thrown", type.getSimpleName())); + return null; // For compiler + } + protected void assertBDocContainer(Container container) { Assert.assertNotNull(container); Assert.assertTrue(container instanceof BDocContainer); @@ -522,6 +550,13 @@ protected void assertValidSignature(Signature signature) { Assert.assertTrue(validationResult.getErrors().isEmpty()); } + protected void assertValidSignatureWithWarnings(Signature signature) { + ValidationResult validationResult = signature.validateSignature(); + Assert.assertTrue(validationResult.isValid()); + Assert.assertTrue(validationResult.hasWarnings()); + Assert.assertTrue(validationResult.getErrors().isEmpty()); + } + protected Policy validCustomPolicy() { Policy customPolicy = new Policy(); customPolicy.setId("id"); diff --git a/digidoc4j/src/test/java/org/digidoc4j/AiaOcspTest.java b/digidoc4j/src/test/java/org/digidoc4j/AiaOcspTest.java index 88c8b8e1f..c68199652 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/AiaOcspTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/AiaOcspTest.java @@ -44,7 +44,7 @@ public void bdocContainerIgnoresAiaOcsp() { Configuration configuration = new Configuration(Configuration.Mode.TEST); configuration.setPreferAiaOcsp(true); File testFile1 = this.createTemporaryFileBy("testFile.txt", "TEST"); - Container container = ContainerBuilder.aContainer() + Container container = ContainerBuilder.aContainer(Container.DocumentType.BDOC) .withDataFile(testFile1.getPath(), "text/plain") .withConfiguration(configuration) .build(); diff --git a/digidoc4j/src/test/java/org/digidoc4j/CertificateValidatorBuilderTest.java b/digidoc4j/src/test/java/org/digidoc4j/CertificateValidatorBuilderTest.java index 018fee759..a5cb4d9c2 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/CertificateValidatorBuilderTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/CertificateValidatorBuilderTest.java @@ -13,6 +13,21 @@ */ public class CertificateValidatorBuilderTest extends AbstractTest { + @Test + public void findOnlyOneIssuerWhenCNAreSame() throws Exception { + CertificateValidator validator = new CertificateValidatorBuilder().withConfiguration(this.configuration).build(); + validator.getCertificateSource().addCertificate(new CertificateToken(this.openX509Certificate(Paths.get + ("src/test/resources/testFiles/certs/sameCN_first.crt")))); + validator.getCertificateSource().addCertificate(new CertificateToken(this.openX509Certificate(Paths.get + ("src/test/resources/testFiles/certs/sameCN_second.crt")))); + try { + validator.validate(this.openX509Certificate(Paths.get("src/test/resources/testFiles/certs/sameCN_first_child.crt"))); + } catch (CertificateValidationException e) { + Assert.assertEquals("Not equals", CertificateValidationException.CertificateValidationStatus.UNKNOWN, e + .getCertificateStatus()); + } + } + @Test public void testCertificateStatusGood() { CertificateValidator validator = new CertificateValidatorBuilder().withConfiguration(this.configuration).build(); @@ -83,7 +98,7 @@ public void testProductionCertificateStatusUnknownWithOCSPResponseVerificationCe public void testLoadingOCSPIntermediateCertificatesFromCustomLocation() { ExtendedCertificateSource source = CertificateValidatorBuilder.getDefaultCertificateSource(); source.importFromPath(Paths.get("src/test/resources/testFiles/certs")); - Assert.assertEquals("Not equals", 10, source.getCertificates().size()); + Assert.assertEquals("Not equals", 13, source.getCertificates().size()); } /* diff --git a/digidoc4j/src/test/java/org/digidoc4j/ConfigurationTest.java b/digidoc4j/src/test/java/org/digidoc4j/ConfigurationTest.java index b5cc2ce8f..960cc78f6 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/ConfigurationTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/ConfigurationTest.java @@ -1137,6 +1137,24 @@ public void verifyAllOptionalConfigurationSettingsAreLoadedFromFile() throws Exc Assert.assertEquals("Set validation policy", this.configuration.getValidationPolicy()); } + @Test + public void getDefaultTempFileMaxAge() throws Exception { + Assert.assertEquals(86400000, this.configuration.getTempFileMaxAge()); + } + + @Test + public void loadTempFileMaxAgeFromFile() throws Exception { + this.configuration.loadConfiguration("src/test/resources/testFiles/yaml-configurations/digidoc_test_conf_temp_file_max_age.yaml"); + Assert.assertEquals(60, this.configuration.getTempFileMaxAge()); + } + + @Test + public void setTempFileMaxAgeFromCode(){ + this.configuration.loadConfiguration("src/test/resources/testFiles/yaml-configurations/digidoc_test_conf_temp_file_max_age.yaml"); + this.configuration.setTempFileMaxAge(1000); + Assert.assertEquals(1000, this.configuration.getTempFileMaxAge()); + } + @Test public void getDefaultConnectionTimeout() throws Exception { Assert.assertEquals(1000, this.configuration.getConnectionTimeout()); diff --git a/digidoc4j/src/test/java/org/digidoc4j/ContainerBuilderTest.java b/digidoc4j/src/test/java/org/digidoc4j/ContainerBuilderTest.java index a372249e3..0274eb068 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/ContainerBuilderTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/ContainerBuilderTest.java @@ -15,6 +15,8 @@ import org.apache.commons.lang3.StringUtils; import org.digidoc4j.exceptions.InvalidDataFileException; import org.digidoc4j.exceptions.NotSupportedException; +import org.digidoc4j.exceptions.TechnicalException; +import org.digidoc4j.impl.asic.asice.AsicEContainer; import org.digidoc4j.impl.asic.asice.bdoc.BDocContainer; import org.digidoc4j.impl.ddoc.DDocContainer; import org.digidoc4j.test.CustomConfiguration; @@ -27,6 +29,8 @@ import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipFile; @@ -42,7 +46,7 @@ public class ContainerBuilderTest extends AbstractTest { public void buildEmptyContainer() throws Exception { ContainerBuilder builder = ContainerBuilder.aContainer(); Container container = builder.build(); - Assert.assertEquals("BDOC", container.getType()); + Assert.assertEquals("ASICE", container.getType()); Assert.assertTrue(container.getDataFiles().isEmpty()); Assert.assertTrue(container.getSignatures().isEmpty()); } @@ -56,7 +60,7 @@ public void buildEmptyDDocContainer() throws Exception { public void buildBDocContainer() throws Exception { this.configuration = new Configuration(Configuration.Mode.TEST); this.configuration.setTspSource("test-value"); - Container container = ContainerBuilder.aContainer().withConfiguration(this.configuration).build(); + Container container = ContainerBuilder.aContainer(BDOC).withConfiguration(this.configuration).build(); BDocContainer bDocContainer = (BDocContainer) container; Assert.assertEquals("BDOC", container.getType()); Assert.assertEquals("test-value", bDocContainer.getConfiguration().getTspSource()); @@ -68,9 +72,9 @@ public void buildBDocContainerWithDataFiles() throws Exception { File testFile2 = this.createTemporaryFileBy("testFile2.txt", "TEST"); LargeDataFile largeDataFile = new LargeDataFile(new ByteArrayInputStream(new byte[]{1, 2, 3}), "largeStreamFile.txt", "text/plain"); Container container = ContainerBuilder.aContainer().withDataFile(testFile1.getPath(), "text/plain"). - withDataFile(new ByteArrayInputStream(new byte[]{1, 2, 3}), "streamFile.txt", "text/plain"). - withDataFile(this.createTemporaryFileBy("ExampleFile.txt", "TEST"), "text/plain"). - withDataFile(new DataFile(testFile2.getPath(), "text/plain")).withDataFile(largeDataFile).build(); + withDataFile(new ByteArrayInputStream(new byte[]{1, 2, 3}), "streamFile.txt", "text/plain"). + withDataFile(this.createTemporaryFileBy("ExampleFile.txt", "TEST"), "text/plain"). + withDataFile(new DataFile(testFile2.getPath(), "text/plain")).withDataFile(largeDataFile).build(); Assert.assertEquals(5, container.getDataFiles().size()); Assert.assertEquals("testFile.txt", container.getDataFiles().get(0).getName()); Assert.assertEquals("streamFile.txt", container.getDataFiles().get(1).getName()); @@ -87,7 +91,7 @@ public void buildContainer_withNullFilePath_shouldThrowException() throws Except @Test(expected = InvalidDataFileException.class) public void buildContainer_withStreamDocAndNullFileName_shouldThrowException() throws Exception { ContainerBuilder.aContainer().withDataFile(new ByteArrayInputStream(new byte[]{1, 2, 3}), null, "text/plain"). - build(); + build(); } @Test(expected = InvalidDataFileException.class) @@ -98,7 +102,7 @@ public void buildContainer_withNullMimeType_shouldThrowException() throws Except @Test public void buildContainer_withInvalidMimeType_shouldSucceed() { Container container = ContainerBuilder.aContainer(). - withDataFile("src/test/resources/testFiles/helper-files/test.txt", "application\\rtf").build(); + withDataFile("src/test/resources/testFiles/helper-files/test.txt", "application\\rtf").build(); Assert.assertTrue(container.validate().isValid()); } @@ -167,7 +171,7 @@ public void buildCustomContainerWithCustomImplementation() throws Exception { @Test public void overrideExistingBDocContainerImplementation() throws Exception { - ContainerBuilder.setContainerImplementation("BDOC", CustomContainer.class); + ContainerBuilder.setContainerImplementation("ASICE", CustomContainer.class); Container container = ContainerBuilder.aContainer().build(); Assert.assertEquals("TEST-FORMAT", container.getType()); } @@ -177,17 +181,17 @@ public void overrideExistingBDocContainerImplementation() throws Exception { public void useExtendedBDocContainerImplementation() throws Exception { ContainerBuilder.setContainerImplementation("BDOC", BDocContainer.class); Container container = ContainerBuilder. - aContainer("BDOC"). - build(); + aContainer("BDOC"). + build(); Assert.assertEquals("BDOC-EXTENDED", container.getType()); } @Test public void clearCustomContainerImplementations_shouldUseDefaultContainerImplementation() throws Exception { - ContainerBuilder.setContainerImplementation("BDOC", BDocContainer.class); + ContainerBuilder.setContainerImplementation("ASICE", AsicEContainer.class); ContainerBuilder.removeCustomContainerImplementations(); Container container = ContainerBuilder.aContainer().build(); - Assert.assertEquals("BDOC", container.getType()); + Assert.assertEquals("ASICE", container.getType()); } @Test @@ -195,7 +199,7 @@ public void createCustomContainerWithConfiguration() throws Exception { this.configuration = Configuration.of(Configuration.Mode.TEST); ContainerBuilder.setContainerImplementation("TEST-FORMAT", CustomContainer.class); Container container = ContainerBuilder.aContainer("TEST-FORMAT"). - withConfiguration(this.configuration).build(); + withConfiguration(this.configuration).build(); Assert.assertEquals("TEST-FORMAT", container.getType()); Assert.assertSame(this.configuration, ((CustomContainer) container).getConfiguration()); } @@ -205,7 +209,7 @@ public void createCustomContainerWithCustomConfiguration() throws Exception { ContainerBuilder.setContainerImplementation("TEST-FORMAT", CustomContainer.class); CustomConfiguration configuration = new CustomConfiguration(); Container container = ContainerBuilder.aContainer("TEST-FORMAT"). - withConfiguration(configuration).build(); + withConfiguration(configuration).build(); Assert.assertEquals("TEST-FORMAT", container.getType()); Assert.assertSame(configuration, ((CustomContainer) container).getConfiguration()); } @@ -221,7 +225,7 @@ public void openDefaultContainerFromFileWithConfiguration() throws Exception { this.configuration = new Configuration(Configuration.Mode.TEST); this.configuration.setTspSource("test-value"); Container container = ContainerBuilder.aContainer().withConfiguration(this.configuration). - fromExistingFile(BDOC_WITH_TM_SIG).build(); + fromExistingFile(BDOC_WITH_TM_SIG).build(); TestAssert.assertContainerIsOpened(container, Container.DocumentType.BDOC); Assert.assertEquals("test-value", ((BDocContainer) container).getConfiguration().getTspSource()); } @@ -253,7 +257,7 @@ public void openCustomContainerFromFile_withConfiguration() throws Exception { File testFile = this.createTemporaryFileBy("testFile.txt", "TEST"); ContainerBuilder.setContainerImplementation("TEST-FORMAT", CustomContainer.class); Container container = ContainerBuilder.aContainer("TEST-FORMAT").withConfiguration(this.configuration). - fromExistingFile(testFile.getPath()).build(); + fromExistingFile(testFile.getPath()).build(); Assert.assertEquals("TEST-FORMAT", container.getType()); Assert.assertEquals(testFile.getPath(), ((CustomContainer) container).getOpenedFromFile()); Assert.assertSame(this.configuration, ((CustomContainer) container).getConfiguration()); @@ -265,7 +269,7 @@ public void openCustomContainerFromFile_withCustomConfiguration() throws Excepti File testFile = this.createTemporaryFileBy("testFile.txt", "TEST"); ContainerBuilder.setContainerImplementation("TEST-FORMAT", CustomContainer.class); Container container = ContainerBuilder.aContainer("TEST-FORMAT").withConfiguration(configuration). - fromExistingFile(testFile.getPath()).build(); + fromExistingFile(testFile.getPath()).build(); Assert.assertEquals("TEST-FORMAT", container.getType()); Assert.assertEquals(testFile.getPath(), ((CustomContainer) container).getOpenedFromFile()); Assert.assertSame(configuration, ((CustomContainer) container).getConfiguration()); @@ -300,8 +304,8 @@ public void openBDocContainerFromStream_withConfiguration() throws Exception { this.configuration.setTspSource("test-value"); InputStream stream = FileUtils.openInputStream(new File(BDOC_WITH_TM_SIG)); Container container = ContainerBuilder.aContainer(Container.DocumentType.BDOC). - withConfiguration(this.configuration). - fromStream(stream).build(); + withConfiguration(this.configuration). + fromStream(stream).build(); TestAssert.assertContainerIsOpened(container, Container.DocumentType.BDOC); assertBDocContainer(container); Assert.assertEquals("test-value", container.getConfiguration().getTspSource()); @@ -311,9 +315,9 @@ public void openBDocContainerFromStream_withConfiguration() throws Exception { public void openBDocContainerWithBEpesSignatureFromStream_withConfiguration() throws Exception { InputStream stream = FileUtils.openInputStream(new File(BDOC_WITH_B_EPES_SIG)); Container container = ContainerBuilder.aContainer(Container.DocumentType.BDOC) - .withConfiguration(this.configuration) - .fromStream(stream) - .build(); + .withConfiguration(this.configuration) + .fromStream(stream) + .build(); TestAssert.assertContainerIsOpened(container, Container.DocumentType.BDOC); assertBDocContainer(container); assertBEpesSignature(container.getSignatures().get(0)); @@ -399,7 +403,7 @@ public void openDDocContainerFromStream_withConfiguration() throws Exception { this.configuration = Configuration.of(Configuration.Mode.TEST); try (InputStream stream = FileUtils.openInputStream(new File(DDOC_TEST_FILE))) { Container container = ContainerBuilder.aContainer(DDOC).withConfiguration(this.configuration). - fromStream(stream).build(); + fromStream(stream).build(); TestAssert.assertContainerIsOpened(container, DDOC); Assert.assertSame(this.configuration, ((DDocContainer) container).getDDoc4JFacade().getConfiguration()); } @@ -409,7 +413,7 @@ public void openDDocContainerFromStream_withConfiguration() throws Exception { public void openDefaultContainerFromStream_withDDOC() throws Exception { InputStream stream = FileUtils.openInputStream(new File(DDOC_TEST_FILE)); Container container = ContainerBuilder.aContainer().withConfiguration(Configuration.of(Configuration.Mode.TEST)). - fromStream(stream).build(); + fromStream(stream).build(); TestAssert.assertContainerIsOpened(container, DDOC); } @@ -428,7 +432,7 @@ public void openCustomContainerFromStream_withConfiguration() throws Exception { InputStream stream = FileUtils.openInputStream(this.createTemporaryFileBy("testFile.txt", "TEST")); ContainerBuilder.setContainerImplementation("TEST-FORMAT", CustomContainer.class); Container container = ContainerBuilder.aContainer("TEST-FORMAT").withConfiguration(this.configuration). - fromStream(stream).build(); + fromStream(stream).build(); Assert.assertEquals("TEST-FORMAT", container.getType()); Assert.assertSame(stream, ((CustomContainer) container).getOpenedFromStream()); Assert.assertSame(this.configuration, ((CustomContainer) container).getConfiguration()); @@ -440,7 +444,7 @@ public void openCustomContainerFromStream_withCustomConfiguration() throws Excep InputStream stream = FileUtils.openInputStream(this.createTemporaryFileBy("testFile.txt", "TEST")); ContainerBuilder.setContainerImplementation("TEST-FORMAT", CustomContainer.class); Container container = ContainerBuilder.aContainer("TEST-FORMAT").withConfiguration(this.configuration). - fromStream(stream).build(); + fromStream(stream).build(); Assert.assertEquals("TEST-FORMAT", container.getType()); Assert.assertSame(stream, ((CustomContainer) container).getOpenedFromStream()); Assert.assertSame(this.configuration, ((CustomContainer) container).getConfiguration()); @@ -451,8 +455,8 @@ public void openDDocContainerWithTempDirectory() throws Exception { File folder = this.testFolder.newFolder(); Assert.assertTrue(folder.list().length == 0); ContainerBuilder.aContainer(DDOC). - fromExistingFile("src/test/resources/testFiles/valid-containers/ddoc_for_testing.ddoc"). - usingTempDirectory(folder.getPath()).build(); + fromExistingFile("src/test/resources/testFiles/valid-containers/ddoc_for_testing.ddoc"). + usingTempDirectory(folder.getPath()).build(); Assert.assertTrue(folder.list().length > 0); } @@ -461,8 +465,8 @@ public void openDDocContainerWithTempDirectoryAndConfiguration() throws Exceptio File folder = this.testFolder.newFolder(); Assert.assertTrue(folder.list().length == 0); ContainerBuilder.aContainer(DDOC). - fromExistingFile("src/test/resources/testFiles/valid-containers/ddoc_for_testing.ddoc"). - withConfiguration(Configuration.of(Configuration.Mode.TEST)).usingTempDirectory(folder.getPath()).build(); + fromExistingFile("src/test/resources/testFiles/valid-containers/ddoc_for_testing.ddoc"). + withConfiguration(Configuration.of(Configuration.Mode.TEST)).usingTempDirectory(folder.getPath()).build(); Assert.assertTrue(folder.list().length > 0); } @@ -472,7 +476,7 @@ public void openDDocContainerFromStreamWithTempDirectory() throws Exception { Assert.assertTrue(folder.list().length == 0); InputStream stream = FileUtils.openInputStream(new File(DDOC_TEST_FILE)); ContainerBuilder.aContainer(DDOC).fromStream(stream). - usingTempDirectory(folder.getPath()).build(); + usingTempDirectory(folder.getPath()).build(); Assert.assertTrue(folder.list().length > 0); } @@ -482,26 +486,63 @@ public void openDDocContainerFromStreamWithTempDirectoryAndConfiguration() throw Assert.assertTrue(folder.list().length == 0); InputStream stream = FileUtils.openInputStream(new File(DDOC_TEST_FILE)); ContainerBuilder.aContainer(DDOC).withConfiguration(Configuration.of(Configuration.Mode.TEST)) - .fromStream(stream).usingTempDirectory(folder.getPath()).build(); + .fromStream(stream).usingTempDirectory(folder.getPath()).build(); Assert.assertTrue(folder.list().length > 0); } @Test public void openBOMBeginningDDocContainerFromPath() { Container container = ContainerBuilder.aContainer() - .fromExistingFile("src/test/resources/testFiles/valid-containers/BOM_algusega.ddoc") - .build(); + .fromExistingFile("src/test/resources/testFiles/valid-containers/BOM_algusega.ddoc") + .build(); Assert.assertTrue(container.validate().isValid()); } @Test public void openBOMBeginningDDocContainerFromStream() throws IOException { Container container = ContainerBuilder.aContainer() - .fromStream(FileUtils.openInputStream(new File("src/test/resources/testFiles/valid-containers/BOM_algusega.ddoc"))) - .build(); + .fromStream(FileUtils.openInputStream(new File("src/test/resources/testFiles/valid-containers/BOM_algusega.ddoc"))) + .build(); Assert.assertTrue(container.validate().isValid()); } + @Test + public void containerBuilder_streamWithZipBomb() throws FileNotFoundException { + this.expectedException.expect(TechnicalException.class); + this.expectedException.expectMessage("Zip Bomb detected in the ZIP container. Validation is interrupted."); + ContainerBuilder.aContainer(). + fromStream(new FileInputStream("src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc")).build(); + } + + @Test + public void containerBuilder_fileWithZipBomb() { + this.expectedException.expect(TechnicalException.class); + this.expectedException.expectMessage("Zip Bomb detected in the ZIP container. Validation is interrupted."); + ContainerBuilder.aContainer(). + fromExistingFile("src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc").build(); + } + + @Test + public void containerBuilder_streamWithNestedZipBomb_multipleFiles() throws FileNotFoundException { + Container container = ContainerBuilder.aContainer(). + fromStream(new FileInputStream("src/test/resources/testFiles/invalid-containers/zip-bomb.asice")).build(); + Assert.assertEquals(17, container.getDataFiles().size()); + } + + @Test + public void containerBuilder_fileWithNestedZipBomb_multipleFiles() { + Container container = ContainerBuilder.aContainer(). + fromExistingFile("src/test/resources/testFiles/invalid-containers/zip-bomb.asice").build(); + Assert.assertEquals(17, container.getDataFiles().size()); + } + + @Test + public void containerBuilder_streamWithNestedZipBomb() throws FileNotFoundException { + Container container = ContainerBuilder.aContainer(). + fromStream(new FileInputStream("src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip.asics")).build(); + Assert.assertEquals(1, container.getDataFiles().size()); + } + /* * RESTRICTED METHODS */ diff --git a/digidoc4j/src/test/java/org/digidoc4j/ContainerOpenerTest.java b/digidoc4j/src/test/java/org/digidoc4j/ContainerOpenerTest.java index 238d09391..7eb42302f 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/ContainerOpenerTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/ContainerOpenerTest.java @@ -12,6 +12,7 @@ import org.apache.commons.io.FileUtils; import org.digidoc4j.exceptions.DigiDoc4JException; +import org.digidoc4j.exceptions.TechnicalException; import org.digidoc4j.test.TestAssert; import org.junit.Assert; import org.junit.Ignore; @@ -19,6 +20,7 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; public class ContainerOpenerTest extends AbstractTest { @@ -145,16 +147,6 @@ public void testErrorText75NotChanged() { } } - @Test - public void testErrorText75ChangedAndNullPointer() { - try { - ContainerBuilder.aContainer().fromExistingFile("src/test/resources/testFiles/invalid-containers/23133_ddoc-12.ddoc"). - build(); - } catch (DigiDoc4JException e) { - Assert.assertTrue(e.getMessage().contains("Invalid input file format.")); - } - } - @Test public void testErrorText75AndInvalidPath() { try { @@ -180,6 +172,35 @@ public void testSignatureXMLContainsTrailingContent() { ContainerOpener.open("src/test/resources/testFiles/valid-containers/signature_xml_contains_trailing_content.bdoc"); } + @Test + public void containerOpener_fileWithZipBomb() { + this.expectedException.expect(TechnicalException.class); + this.expectedException.expectMessage("Zip Bomb detected in the ZIP container. Validation is interrupted."); + ContainerOpener.open("src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc"); + } + + @Test + public void containerOpener_fileWithZipBomb_fileCachedInMemory() { + this.expectedException.expect(TechnicalException.class); + this.expectedException.expectMessage("Zip Bomb detected in the ZIP container. Validation is interrupted."); + configuration.setMaxFileSizeCachedInMemoryInMB(1); + ContainerOpener.open("src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc"); + } + + @Test + public void containerOpener_streamWithZipBomb() throws FileNotFoundException { + this.expectedException.expect(TechnicalException.class); + this.expectedException.expectMessage("Zip Bomb detected in the ZIP container. Validation is interrupted."); + ContainerOpener.open(new FileInputStream("src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc"), this.configuration); + } + + @Test + public void containerOpener_streamWithZipBomb_fileCachedInMemory() throws FileNotFoundException { + this.expectedException.expectMessage("Zip Bomb detected in the ZIP container. Validation is interrupted."); + configuration.setMaxFileSizeCachedInMemoryInMB(1); + ContainerOpener.open(new FileInputStream("src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc"), this.configuration); + } + /* * RESTRICTED METHODS */ diff --git a/digidoc4j/src/test/java/org/digidoc4j/ContainerTest.java b/digidoc4j/src/test/java/org/digidoc4j/ContainerTest.java index 4107a9832..a179db510 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/ContainerTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/ContainerTest.java @@ -12,6 +12,7 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.digidoc4j.exceptions.DataFileNotFoundException; import org.digidoc4j.exceptions.DigiDoc4JException; @@ -20,6 +21,8 @@ import org.digidoc4j.exceptions.OCSPRequestFailedException; import org.digidoc4j.exceptions.RemovingDataFileException; import org.digidoc4j.impl.asic.asice.bdoc.BDocContainer; +import org.digidoc4j.impl.asic.asice.bdoc.BDocContainerBuilder; +import org.digidoc4j.impl.asic.manifest.AsicManifest; import org.digidoc4j.impl.ddoc.ConfigManagerInitializer; import org.digidoc4j.impl.ddoc.DDocContainer; import org.digidoc4j.test.TestAssert; @@ -34,10 +37,13 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.security.cert.CertificateEncodingException; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public class ContainerTest extends AbstractTest { @@ -134,6 +140,32 @@ public void testAddOneFileToContainerForBDoc() throws Exception { Assert.assertEquals("text/plain", dataFiles.get(0).getMediaType()); } + @Test + public void removeDataFileRemovesFileFromManifest() throws IOException { + Container nonEmptyContainer = this.createNonEmptyContainer(); + Container container = BDocContainerBuilder + .aContainer() + .fromStream(nonEmptyContainer.saveAsStream()) + .withConfiguration(configuration) + .build(); + + container.removeDataFile(container.getDataFiles().get(0)); + + InputStream inputStream = container.saveAsStream(); + boolean manifestVerified = false; + try (ZipInputStream zis = new ZipInputStream(inputStream)) { + ZipEntry zipEntry; + while ((zipEntry = zis.getNextEntry()) != null) { + if (zipEntry.getName().equals(AsicManifest.XML_PATH)) { + manifestVerified = true; + String manifestContent = IOUtils.toString(zis, StandardCharsets.UTF_8); + Assert.assertFalse(manifestContent.contains(" new DataFile(new byte[]{0x041}, fileName, "text/plain")); + } + @Test public void testGetBytes() throws Exception { DataFile dataFile = new DataFile(new byte[]{0x041}, "suura.txt", "text/plain"); @@ -130,12 +179,31 @@ public void createDocumentFromStream() throws Exception { @Test public void createDocumentFromInoutStreamThrowsException() throws IOException { try (ByteArrayInputStream stream = new ByteArrayInputStream("test".getBytes())) { - this.dataFile = new DataFile(stream, "test.txt", "unknown"); - Assert.assertNotNull(this.dataFile.getMediaType()); + DataFile dataFile = new DataFile(stream, "test.txt", "unknown"); + Assert.assertNotNull(dataFile.getMediaType()); Assert.assertArrayEquals("test".getBytes(), dataFile.getBytes()); } } + @Test + public void testGetFileNameForStreamedFile() throws Exception { + try (ByteArrayInputStream stream = new ByteArrayInputStream("tere tere tipajalga".getBytes())) { + DataFile dataFile = new DataFile(stream, "test.txt", "text/plain"); + Assert.assertEquals("test.txt", dataFile.getName()); + } + } + + @Test + public void testFileNameEscapingForStreamedFile() { + testFileNameEscaping(fileName -> { + try (ByteArrayInputStream stream = new ByteArrayInputStream("tere tere tipajalga".getBytes())) { + return new DataFile(stream, fileName, "text/plain"); + } catch (IOException e) { + throw new IllegalStateException("Failed to open stream", e); + } + }); + } + @Test public void calculateSizeForStreamedFile() throws Exception { try (ByteArrayInputStream stream = new ByteArrayInputStream("tere tere tipajalga".getBytes())) { @@ -146,17 +214,30 @@ public void calculateSizeForStreamedFile() throws Exception { @Test public void testDigestIsCalculatedOnlyOnce() throws Exception { - byte[] digest = this.dataFile.calculateDigest(); - Assert.assertEquals(digest, this.dataFile.calculateDigest(new URL("http://NonExisting.test"))); + DataFile dataFile = new DataFile(TEST_FILE_PATH, TEST_FILE_MIMETYPE); + byte[] digest = dataFile.calculateDigest(); + Assert.assertEquals(digest, dataFile.calculateDigest(new URL("http://NonExisting.test"))); } /* * RESTRICTED METHODS */ - @Override - protected void before() { - this.dataFile = new DataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); + private static void testFileNameEscaping(Function dataFileFactory) { + String fileName = "file-name.ext"; + DataFile dataFile; + + dataFile = dataFileFactory.apply(fileName); + Assert.assertEquals(fileName, dataFile.getName()); + + dataFile = dataFileFactory.apply(String.format("dir%s%s", File.separator, fileName)); + Assert.assertEquals(fileName, dataFile.getName()); + + dataFile = dataFileFactory.apply(String.format("..%s%s", File.separator, fileName)); + Assert.assertEquals(fileName, dataFile.getName()); + + dataFile = dataFileFactory.apply(String.format("..%s..%sdir%s..%s%s", File.separator, File.separator, File.separator, File.separator, fileName)); + Assert.assertEquals(fileName, dataFile.getName()); } } diff --git a/digidoc4j/src/test/java/org/digidoc4j/DetachedXadesSignatureBuilderTest.java b/digidoc4j/src/test/java/org/digidoc4j/DetachedXadesSignatureBuilderTest.java index 62e471a09..8248b76a8 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/DetachedXadesSignatureBuilderTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/DetachedXadesSignatureBuilderTest.java @@ -6,13 +6,13 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.SerializationUtils; +import org.digidoc4j.exceptions.InvalidDataFileException; import org.digidoc4j.exceptions.InvalidSignatureException; import org.digidoc4j.exceptions.NotSupportedException; import org.digidoc4j.exceptions.SignatureTokenMissingException; import org.digidoc4j.exceptions.SignerCertificateRequiredException; import org.digidoc4j.impl.asic.asice.bdoc.BDocSignature; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; public class DetachedXadesSignatureBuilderTest extends AbstractTest { @@ -33,7 +33,7 @@ public void signExternally() throws Exception { byte[] signatureValue = pkcs12EccSignatureToken.sign(deserializedDataToSign.getDigestAlgorithm(), deserializedDataToSign.getDataToSign()); Signature signature = dataToSign.finalize(signatureValue); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -47,7 +47,7 @@ public void signWithSignatureToken() throws Exception { .invokeSigning(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -79,7 +79,7 @@ public void signWithMultipleDataFiles() throws Exception { .invokeSigning(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -92,7 +92,25 @@ public void signWithNormalDataFile() { .invokeSigning(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); + } + + @Test(expected = InvalidDataFileException.class) + public void invokeSigningWithEmptyDataFileThrowsException() { + DataFile dataFile = new DataFile(new byte[0], "hello.txt", "text/plain"); + DetachedXadesSignatureBuilder.withConfiguration(new Configuration()) + .withDataFile(dataFile) + .withSignatureToken(pkcs12EccSignatureToken) + .invokeSigning(); + } + + @Test(expected = InvalidDataFileException.class) + public void buildDataToSignWithEmptyDataFileThrowsException() { + DataFile dataFile = new DataFile(new byte[0], "hello.txt", "text/plain"); + DetachedXadesSignatureBuilder.withConfiguration(new Configuration()) + .withDataFile(dataFile) + .withSignatureToken(pkcs12EccSignatureToken) + .invokeSigning(); } @Test(expected = SignatureTokenMissingException.class) @@ -131,7 +149,7 @@ public void signWithLT_TMProfile() throws Exception { .invokeSigningProcess(); assertTimemarkSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -147,8 +165,9 @@ public void signWithB_EPESProfile() throws Exception { assertBEpesSignature(signature); ValidationResult validationResult = signature.validateSignature(); Assert.assertFalse(validationResult.isValid()); - Assert.assertEquals(1, validationResult.getWarnings().size()); + Assert.assertEquals(2, validationResult.getWarnings().size()); Assert.assertEquals("The signature/seal is an INDETERMINATE AdES digital signature!", validationResult.getWarnings().get(0).getMessage()); + Assert.assertEquals("The authority info access is not present!", validationResult.getWarnings().get(1).getMessage()); Assert.assertEquals(2, validationResult.getErrors().size()); Assert.assertEquals("The result of the LTV validation process is not acceptable to continue the process!", validationResult.getErrors().get(0).getMessage()); Assert.assertEquals("No acceptable revocation data for the certificate!", validationResult.getErrors().get(1).getMessage()); @@ -166,7 +185,7 @@ public void signWithLTProfile() throws Exception { .withSignatureProfile(SignatureProfile.LT) .invokeSigningProcess(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -207,7 +226,7 @@ public void signWithSignerInfo() throws Exception { Assert.assertEquals("myRole / myResolution", signature.getSignerRoles().get(0)); Assert.assertEquals("SIGNATURE-1", signature.getId()); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -224,7 +243,7 @@ public void readExistingSignatureAndValidate() throws Exception { .openAdESSignature(xadesSignature); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -325,7 +344,7 @@ public void mimeTypeValueNotInitialized() throws Exception{ .invokeSigningProcess(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -340,7 +359,7 @@ public void mimeTypeValueNotValidated() throws Exception { .invokeSigningProcess(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); } @Test @@ -358,7 +377,7 @@ public void addDetachedSignatureToContainer() throws Exception { .invokeSigningProcess(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); Container container = ContainerOpener.open(BDOC_WITH_TM_SIG, configuration); container.addSignature(signature); @@ -381,7 +400,7 @@ public void addDetachedSignatureToContainerWithNotMatchingMimeType_validationSho .invokeSigningProcess(); assertTimestampSignature(signature); - assertValidSignature(signature); + assertValidSignatureWithWarnings(signature); Container container = ContainerOpener.open(BDOC_WITH_TM_SIG, configuration); container.addSignature(signature); diff --git a/digidoc4j/src/test/java/org/digidoc4j/SignatureBuilderTest.java b/digidoc4j/src/test/java/org/digidoc4j/SignatureBuilderTest.java index e8be5edf2..c7fdf0783 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/SignatureBuilderTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/SignatureBuilderTest.java @@ -91,11 +91,11 @@ public void signDocumentExternallyTwice() throws Exception { Container container = this.createNonEmptyContainer(); DataToSign dataToSign = TestDataBuilderUtil.buildDataToSign(container, "S0"); Signature signature = TestDataBuilderUtil.makeSignature(container, dataToSign); - this.assertSignatureIsValid(signature); + this.assertSignatureIsValid(signature, SignatureProfile.LT); DataToSign dataToSign2 = TestDataBuilderUtil.buildDataToSign(container, "S1"); Signature signature2 = TestDataBuilderUtil.makeSignature(container, dataToSign2); - this.assertSignatureIsValid(signature2); - container.saveAsFile(this.getFileBy("bdoc")); + this.assertSignatureIsValid(signature2, SignatureProfile.LT); + container.saveAsFile(this.getFileBy("asice")); } @Test @@ -108,7 +108,7 @@ public void signContainerWithSignatureToken() throws Exception { container.addSignature(signature); Assert.assertTrue(signature.validateSignature().isValid()); container.saveAsFile(this.getFileBy("bdoc")); - this.assertSignatureIsValid(signature); + this.assertSignatureIsValid(signature, SignatureProfile.LT_TM); Assert.assertEquals("Tallinn", signature.getCity()); Assert.assertEquals("Harjumaa", signature.getStateOrProvince()); Assert.assertEquals("13456", signature.getPostalCode()); @@ -897,9 +897,9 @@ private Signature openAdESSignature(Container container) throws IOException { return SignatureBuilder.aSignature(container).openAdESSignature(signatureBytes); } - private void assertSignatureIsValid(Signature signature) { + private void assertSignatureIsValid(Signature signature, SignatureProfile expectedSignatureProfile) { Assert.assertNotNull(signature.getOCSPResponseCreationTime()); - Assert.assertEquals(SignatureProfile.LT_TM, signature.getProfile()); + Assert.assertEquals(expectedSignatureProfile, signature.getProfile()); Assert.assertNotNull(signature.getClaimedSigningTime()); Assert.assertNotNull(signature.getAdESSignature()); Assert.assertTrue(signature.getAdESSignature().length > 1); diff --git a/digidoc4j/src/test/java/org/digidoc4j/SignatureTest.java b/digidoc4j/src/test/java/org/digidoc4j/SignatureTest.java index f8260b732..6821402aa 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/SignatureTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/SignatureTest.java @@ -318,7 +318,7 @@ public void testGetTimeStampTokenCertificateForDDoc() { @Test public void testGetNonceForBDoc() { Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/valid-bdoc-tm.bdoc"); - String nonce = Base64.encodeBase64String(container.getSignatures().get(0).getOCSPNonce()); + String nonce = Base64.encodeBase64String(container.getSignatures().get(0).getOCSPNonce()); Assert.assertEquals("MDEwDQYJYIZIAWUDBAIBBQAEIGYrFuVObKYFoA8P22TxZ8knTH4dLASQ2hEG5ejvV1gK", nonce); } @@ -428,27 +428,12 @@ public void gettingOcspCertificate_whenTslIsNotLoaded() throws Exception { } @Test - @Ignore("DD4J-469") - public void checkCertificateSSCDSupport() { + public void certificateContainsNotSupportedTssQcQualifier() { this.configuration = new Configuration(Configuration.Mode.PROD); - TslManager tslManager = new TslManager(this.configuration); - TSLCertificateSource certificateSource = tslManager.getTsl(); - this.configuration.setTSL(certificateSource); - DSSDocument document = new FileDocument( - "src/test/resources/prodFiles/invalid-containers/edoc2_lv-eId_sha256.edoc"); - SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(document); - SKCommonCertificateVerifier verifier = new SKCommonCertificateVerifier(); - OCSPSource ocspSource = OCSPSourceBuilder.anOcspSource().withConfiguration(this.configuration).build(); - verifier.setOcspSource(ocspSource); - verifier.setTrustedCertSource(this.configuration.getTSL()); - verifier.setDataLoader(new CommonsDataLoader()); - validator.setCertificateVerifier(verifier); - Reports reports = validator.validateDocument(); - boolean isValid = true; - for (String signatureId : reports.getSimpleReport().getSignatureIdList()) { - isValid = isValid && reports.getSimpleReport().isValid(signatureId); - } - Assert.assertTrue(isValid); + Container container = this.openContainerByConfiguration( + Paths.get("src/test/resources/prodFiles/invalid-containers/edoc2_lv-eId_sha256.edoc"), + this.configuration); + Assert.assertFalse(container.validate().isValid()); } @Test diff --git a/digidoc4j/src/test/java/org/digidoc4j/X509CertTest.java b/digidoc4j/src/test/java/org/digidoc4j/X509CertTest.java index 7aaaf4a7a..b6080e9d1 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/X509CertTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/X509CertTest.java @@ -27,20 +27,20 @@ public class X509CertTest { - private final X509Cert certificate = new X509Cert("src/test/resources/testFiles/certs/signout.pem"); + private final X509Cert certificate = new X509Cert("src/test/resources/testFiles/certs/sign_RSA_from_TEST_of_ESTEIDSK2015.pem"); private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); @Test public void testGetX509Certificate() throws Exception { X509Certificate x509Certificate = this.certificate.getX509Certificate(); - Assert.assertEquals("SERIALNUMBER=11404176865, GIVENNAME=MÄRÜ-LÖÖZ, SURNAME=ŽÕRINÜWŠKY, " + - "CN=\"ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865\", OU=digital signature, O=ESTEID, C=EE", + Assert.assertEquals("SERIALNUMBER=60001013739, GIVENNAME=MARY ÄNN, SURNAME=O’CONNEŽ-ŠUSLIK TESTNUMBER, " + + "CN=\"O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739\", C=EE", x509Certificate.getSubjectDN().getName()); } @Test public void testGetSerialNumber() { - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", this.certificate.getSerial()); + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", this.certificate.getSerial()); } @Test @@ -59,7 +59,7 @@ public void testGetIssuerNameByPart() { @Test public void testGetPolicies() throws IOException { - Assert.assertEquals(1, this.certificate.getCertificatePolicies().size()); + Assert.assertEquals(2, this.certificate.getCertificatePolicies().size()); } @Test @@ -105,19 +105,19 @@ public void testKeyUsage() { @Test public void testGetPartOfSubjectName() throws Exception { - Assert.assertEquals("11404176865", this.certificate.getSubjectName(X509Cert.SubjectName.SERIALNUMBER)); - Assert.assertEquals("märü-lööz", this.certificate.getSubjectName(X509Cert.SubjectName.GIVENNAME).toLowerCase()); - Assert.assertEquals("žõrinüwšky", this.certificate.getSubjectName(X509Cert.SubjectName.SURNAME).toLowerCase()); - Assert.assertEquals("\"žõrinüwšky,märü-lööz,11404176865\"", this.certificate.getSubjectName(X509Cert.SubjectName.CN).toLowerCase()); - Assert.assertEquals("digital signature", this.certificate.getSubjectName(X509Cert.SubjectName.OU).toLowerCase()); - Assert.assertEquals("esteid", this.certificate.getSubjectName(X509Cert.SubjectName.O).toLowerCase()); + Assert.assertEquals("60001013739", this.certificate.getSubjectName(X509Cert.SubjectName.SERIALNUMBER)); + Assert.assertEquals("mary änn", this.certificate.getSubjectName(X509Cert.SubjectName.GIVENNAME).toLowerCase()); + Assert.assertEquals("o’connež-šuslik testnumber", this.certificate.getSubjectName(X509Cert.SubjectName.SURNAME).toLowerCase()); + Assert.assertEquals("\"o’connež-šuslik testnumber,mary änn,60001013739\"", this.certificate.getSubjectName(X509Cert.SubjectName.CN).toLowerCase()); Assert.assertEquals("ee", this.certificate.getSubjectName(X509Cert.SubjectName.C).toLowerCase()); + Assert.assertNull(this.certificate.getSubjectName(X509Cert.SubjectName.OU)); + Assert.assertNull(this.certificate.getSubjectName(X509Cert.SubjectName.O)); } @Test public void testGetSubjectName() throws Exception { - Assert.assertEquals("SERIALNUMBER=11404176865, GIVENNAME=MÄRÜ-LÖÖZ, SURNAME=ŽÕRINÜWŠKY, CN=\"ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ," + - "11404176865\", OU=digital signature, O=ESTEID, C=EE", this.certificate.getSubjectName()); + Assert.assertEquals("SERIALNUMBER=60001013739, GIVENNAME=MARY ÄNN, SURNAME=O’CONNEŽ-ŠUSLIK TESTNUMBER, " + + "CN=\"O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739\", C=EE", this.certificate.getSubjectName()); } @Test diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/DataToSignSerializationTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/DataToSignSerializationTest.java index d99953e4e..94fed99b7 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/DataToSignSerializationTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/DataToSignSerializationTest.java @@ -147,7 +147,7 @@ public void finalizeSignature_notEmptyContainerFromPath() { ); for (Container container : containers) { - Signature signature = finalizeAndValidateContainerSignature(container, 40000); + Signature signature = finalizeAndValidateContainerSignature(container, 80000); if (!container.getType().equalsIgnoreCase(Container.DocumentType.ASICS.name())) { container.addSignature(signature); } @@ -165,7 +165,7 @@ public void finalizeSignature_notEmptyContainerFromStream() throws FileNotFoundE ); for (Container container: containers) { - Signature signature = finalizeAndValidateContainerSignature(container, 40000); + Signature signature = finalizeAndValidateContainerSignature(container, 80000); if (!container.getType().equalsIgnoreCase(Container.DocumentType.ASICS.name())) { container.addSignature(signature); } @@ -247,6 +247,7 @@ private Signature finalizeAndValidateDetachedSignature(DataFile dataFile, Signat */ private Signature finalizeAndValidateSignature(DataToSign dataToSign, int dataFilesCount, int dataToSignAdditionalWeightInBytes) { byte[] dataToSignSerialized = SerializationUtils.serialize(dataToSign); + assertTrue(dataToSignAdditionalWeightInBytes + 20000 > dataToSignSerialized.length); assertTrue(DATA_TO_SIGN_DIGEST_EXPECTED_CEILING_SIZE * dataFilesCount > dataToSign.getDataToSign().length); diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/EmptyDataFilesSignatureFinalizerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/EmptyDataFilesSignatureFinalizerTest.java new file mode 100644 index 000000000..2016c0a52 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/EmptyDataFilesSignatureFinalizerTest.java @@ -0,0 +1,58 @@ +package org.digidoc4j.impl; + +import org.digidoc4j.AbstractTest; +import org.digidoc4j.DataFile; +import org.digidoc4j.exceptions.InvalidDataFileException; +import org.digidoc4j.test.TestAssert; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public abstract class EmptyDataFilesSignatureFinalizerTest extends AbstractTest { + + protected abstract SignatureFinalizer createSignatureFinalizerWithDataFiles(List dataFiles); + + @Test + public void testCreateSignatureFinalizerWithSingleEmptyDataFile() { + List dataFiles = Arrays.asList( + new DataFile(new byte[0], "empty-file.txt", "text/plain") + ); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> createSignatureFinalizerWithDataFiles(dataFiles) + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class); + } + + @Test + public void testCreateSignatureFinalizerWithMultipleEmptyDataFiles() { + List dataFiles = Arrays.asList( + new DataFile(new byte[1], "data-file-1.txt", "text/plain"), + new DataFile(new byte[0], "empty-file-2.txt", "text/plain"), + new DataFile(new byte[1], "data-file-3.txt", "text/plain"), + new DataFile(new byte[1], "data-file-4.txt", "text/plain"), + new DataFile(new byte[0], "empty-file-5.txt", "text/plain"), + new DataFile(new byte[1], "data-file-6.txt", "text/plain"), + new DataFile(new byte[0], "empty-file-7.txt", "text/plain"), + new DataFile(new byte[0], "empty-file-8.txt", "text/plain") + ); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> createSignatureFinalizerWithDataFiles(dataFiles) + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file-2.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class, + "Cannot sign empty datafile: empty-file-5.txt", + "Cannot sign empty datafile: empty-file-7.txt", + "Cannot sign empty datafile: empty-file-8.txt" + ); + } + +} \ No newline at end of file diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/SKOnlineOCSPSourceTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/SKOnlineOCSPSourceTest.java index 74d21f042..e469e7c07 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/SKOnlineOCSPSourceTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/SKOnlineOCSPSourceTest.java @@ -12,44 +12,36 @@ import eu.europa.esig.dss.enumerations.CertificateStatus; import eu.europa.esig.dss.model.DSSException; +import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.spi.DSSRevocationUtils; import eu.europa.esig.dss.spi.DSSUtils; import eu.europa.esig.dss.spi.x509.CertificateSource; -import eu.europa.esig.dss.model.x509.CertificateToken; import eu.europa.esig.dss.spi.x509.revocation.ocsp.OCSPToken; import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.X509v3CertificateBuilder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; -import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.cert.ocsp.BasicOCSPResp; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.x509.X509V3CertificateGenerator; import org.digidoc4j.AbstractTest; import org.digidoc4j.Configuration; import org.digidoc4j.OCSPSourceBuilder; import org.digidoc4j.ServiceType; -import org.digidoc4j.exceptions.*; +import org.digidoc4j.exceptions.CertificateValidationException; import org.digidoc4j.exceptions.CertificateValidationException.CertificateValidationStatus; -import org.digidoc4j.impl.CommonOCSPCertificateSource; -import org.digidoc4j.impl.SKOnlineOCSPSource; -import org.digidoc4j.impl.SkOCSPDataLoader; +import org.digidoc4j.exceptions.ServiceAccessDeniedException; +import org.digidoc4j.exceptions.ServiceUnavailableException; +import org.digidoc4j.exceptions.TechnicalException; import org.digidoc4j.test.util.TestSigningUtil; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import javax.security.auth.x500.X500Principal; -import java.math.BigInteger; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; -import java.security.*; +import java.security.Security; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -134,8 +126,8 @@ public void getTestCertificateOCSPTokenFromProdOCSP_thenThrowUnknownCertificateV public void ocspAccessSettingsInvalid_throwsServiceAccessDeniedException() throws CertificateEncodingException { Configuration configuration = Configuration.of(TEST); configuration.setSignOCSPRequests(true); - configuration.setOCSPAccessCertificateFileName("src/test/resources/testFiles/p12/signout.p12"); - configuration.setOCSPAccessCertificatePassword("test".toCharArray()); + configuration.setOCSPAccessCertificateFileName(TestSigningUtil.TEST_PKI_CONTAINER); + configuration.setOCSPAccessCertificatePassword(TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD.toCharArray()); SKOnlineOCSPSource ocspSource = (SKOnlineOCSPSource) OCSPSourceBuilder.defaultOCSPSource() .withConfiguration(configuration) @@ -357,6 +349,17 @@ public void getOCSPToken_anyDSSExceptionRethrownAsTechnicalException() { ocspSource.getRevocationToken(new CertificateToken(TestSigningUtil.SIGN_CERT), new CertificateToken(this.issuerCert)); } + @Test + public void ocspResponseWithCaCertificate() throws IOException { + X509Certificate subjectCertificate = openX509Certificate(Paths.get("src/test/resources/testFiles/certs/d-trust-ca.cer")); + this.configuration.getTSL().addTSLCertificate(subjectCertificate); + SKOnlineOCSPSource skOnlineOCSPSource = Mockito.spy(constructOCSPSource()); + BasicOCSPResp basicOCSPResp = DSSRevocationUtils.loadOCSPBase64Encoded( + "MIIRXQoBAKCCEVYwghFSBgkrBgEFBQcwAQEEghFDMIIRPzCCAUqhYTBfMQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSAwHgYDVQQDExdELVRSVVNUIE9DU1AgMiAzLTEgMjAxNjEXMBUGA1UEYRMOTlRSREUtSFJCNzQzNDYYDzIwMTkwMzE1MTA0NzUxWjCBrzCBrDBJMAkGBSsOAwIaBQAEFAbmmcp8gO6BjP+ofF1XAe1qxY9xBBStC4sZrfX9mYllcnDjXG/JQoEJRgIQMvhgOMxbzNo2TwepM/QLKYAAGA8yMDE5MDMxNTEwNDc1MVqhTDBKMBoGBSskCAMMBBEYDzIwMTkwMTMwMDkzMjQ1WjAsBgUrJAgDDQQjMCEwCQYFKw4DAhoFAAQU9dbitxaidPedbKD/hfAL4PHUQxmhIjAgMB4GCSsGAQUFBzABBgQRGA8xOTg5MDMyMjAwMDAwMFowQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgA4IBAQAtt19/YWP5MbRAdlEQTi67686w21aYRLGHTUMHKA7ztLosauZgFkr2CHRYQO6qBOGvw90EB2njMEmcgdviS0+z1UdQdVz7DO6iFY76IIg68Rn9WDCoOoJ48/OaTgKeg9vEc/WfjNZXQ6WwTN1E5//7s8BWjOEe4lGPrM0pt3GLbgwjDBAUKBkjnRJclHCwEG0LA6XZRZ/BIu0He7ScrE2kSzrQg1NM7E2nC+JLZ+qYI5Y9dlOEsrPuL1o3IuJXql3BfZMGRALTvJf1orFIHM6Fqsj9Z6vRytEbYJmr2x/npmX7QoIBxHrRLkfHnhqJ19lwMo0kD3zoqGnERrheJyvOoIIOpTCCDqEwggbbMIIEk6ADAgECAhBxomoaMnOqxOrKgUJHXKJJMD0GCSqGSIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCA6IDAgFAMFsxCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgxHDAaBgNVBAMTE0QtVFJVU1QgQ0EgMy0xIDIwMTYxFzAVBgNVBGETDk5UUkRFLUhSQjc0MzQ2MB4XDTE4MDkxNzE0MDE1MloXDTMxMTAyNjA4MzY1MFowXzELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEgMB4GA1UEAxMXRC1UUlVTVCBPQ1NQIDIgMy0xIDIwMTYxFzAVBgNVBGETDk5UUkRFLUhSQjc0MzQ2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAti1SpBOCYEIsSQpFDn8zZcExN/J42wYNLMAlhWCn8N9gWmYMehJuLUiTHwSf49Qs3nwJDsRLlp6D5R/+t9zJeIxV7q7BB7wqS1AvqCCqNC8K54yOe+yQHRyeFsIhnV6V1cCwVrFvy1UWliDdaVsevoltYQjBgCVPLSFl8Whg6o2yWB7le7KXb0LLeFu8TCNp1048/VYBTuqi6/RtlM4gZO0iKkgAB0QV/pisIR713EvJ+53j8R8YWrulMIQyLp19nktHwFO60O4FPu2qnpqcX617nBccQUlBkvQ3pTTe2nAdBYsOIt+WzAk11BVYyzK2iBFP/UuK/UVSN8iOQOMWaQIDAQABo4ICNTCCAjEwEwYDVR0lBAwwCgYIKwYBBQUHAwkwHwYDVR0jBBgwFoAU++3frUvwJbXSet2fmh0vbQlQIccwgcUGCCsGAQUFBwEBBIG4MIG1MEIGCCsGAQUFBzAChjZodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NnaS1iaW4vRC1UUlVTVF9DQV8zLTFfMjAxNi5jcnQwbwYIKwYBBQUHMAKGY2xkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1UUlVTVCUyMENBJTIwMy0xJTIwMjAxNixPPUQtVHJ1c3QlMjBHbWJILEM9REU/Y0FDZXJ0aWZpY2F0ZT9iYXNlPzCB8AYDVR0fBIHoMIHlMIHioIHfoIHchmlsZGFwOi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBDQSUyMDMtMSUyMDIwMTYsTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3SGMmh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfY2FfMy0xXzIwMTYuY3JshjtodHRwOi8vY2RuLmQtdHJ1c3QtY2xvdWRjcmwubmV0L2NybC9kLXRydXN0X2NhXzMtMV8yMDE2LmNybDAdBgNVHQ4EFgQUoAtmHN3AQBHvlH2b6CG1O4IeYDEwDgYDVR0PAQH/BAQDAgZAMA8GCSsGAQUFBzABBQQCBQAwPQYJKoZIhvcNAQEKMDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMCAUADggIBAKJJ/FoMPzCK7VCWQ1U7vV7N39ieGz0ZIthbd1M3/OzfWW2BDlf6MMXFyYea1E3KH7snpOVMaWrrhbizSYO07MEx7GyjWrHNSOe86AJ9avgYZFF8CMn060fqfkaWirSB0+VjKcg2JSDFlWMVOvnp1IWfSKdQlDgWTXtMhXjtVsXvuyZsR/o+uSbVWpZUbpPdWBwKoLb/K86aStpfGAutfP0C0s1FuBwcKv0kjq+q+fLP6u/NzHTAJb7Vk2YfOwO9AkrZoMux10YhBm1i8kgr/xbh861QNLNRcFwp7nop+xmbJixsRlPDR4t8qrbfGAMTsXrtey6dTQx12w5DNRRv5sBUELwgkluxFlfJYQP65F7QTdRko6rnbpoIBW8jIgk8zyZy0ID8e0Fv3ZYVcsUg1AzyBcaawI8OCT0oY9+M0ETPfuuBDec+tunXvM89Gxp/s8jHDsf+qhEqCG6rgWIiUcECLxMVp0s1hq6tTgOIa4gTzLfVTPFtRzwNcLoHtCXocjb6+t9S7c3i3qj0iPQRX8j6mgkPx74Z5FiL0nkvH0UOofsZih/MT+AqVMyYOvcELgR+MNYTh2j5o6slgAqEqrKnxw+42mmM9Zhi0gUWx5spUU3gY140xHzsHC78QJXtfCt00ZJOpRH289NzMv19Ivs8FeyT7EhUB7ju08p4tfKBMIIHvjCCBXagAwIBAgIDD+R2MD0GCSqGSIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCA6IDAgFAMF4xCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgxHzAdBgNVBAMTFkQtVFJVU1QgUm9vdCBDQSAzIDIwMTYxFzAVBgNVBGETDk5UUkRFLUhSQjc0MzQ2MB4XDTE2MTAyNjA4MzYzOFoXDTMxMTAyNjA4MzY1MFowWzELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEcMBoGA1UEAxMTRC1UUlVTVCBDQSAzLTEgMjAxNjEXMBUGA1UEYRMOTlRSREUtSFJCNzQzNDYwggIgMAsGCSqGSIb3DQEBCgOCAg8AMIICCgKCAgEA0Qf6buWosCBXDA9QBiJjHLYSAYgKOatoXaJMuclKoa1vNueQEKupz5Cw1u5oiyQIlgflJAyUHGNPv4IkpK01QfUFaNYKJswZ+nb3DK0aalbwghzZOBmYJn1qUNVD/G8ZJ4EcFrcHQp78Cuu4UpImNSjeA8Deg3X9i0NDyd0DR/jUjU9Ufwypf+NbklUH7YYfzdgUonKgaPkVr99tjK7lnmUE0nQWa/FHQLFmx40txQbpFst/W6sLw3Dxk9VniZOeZO5/nY6hxP3wPr/H12nCWuHfbQBl0H3ImqQFxvSdHGWaCOwousH+sywrlFaUv3Rtohq9ZVrAaFw3MAOXI9VpZBRh0gXx/tAtGnazQWBbShTGqgXAV8Gb/bHpIZiHA6iip87Sh+cHMUVYbdpowc7svirH5AvsY+5z/kbcmZNS796hvFPf0svJp+CUW8+H8atsCp5WKS7bzCE/bWjhlIUXjDlX8Czac2N9brUaJ/elyhL+iSq0z/Lrx/iH4SlkmZy5bdxGd9vdYaTTHineTVVydtr/gwwrXpE92vKntLYQ2BDLLU6JKCzCRPJntdLCdr8lDY9hDMF+EMaw9EIYmNqdRl/UEldzoJQSf1oIGxNCb+K2tFKl9iL+9f6N5k9mblbF9j0uKkyLUHZJnRhWoaOEyRR/Uyy+62cvCfcnCpjofsMCAwEAAaOCAigwggIkMB8GA1UdIwQYMBaAFNzAEr2IPWMTjDSr286LMsQRTl3nMIGJBggrBgEFBQcBAQR9MHswMgYIKwYBBQUHMAGGJmh0dHA6Ly9yb290LWNhLTMtMjAxNi5vY3NwLmQtdHJ1c3QubmV0MEUGCCsGAQUFBzAChjlodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NnaS1iaW4vRC1UUlVTVF9Sb290X0NBXzNfMjAxNi5jcnQwcQYDVR0gBGowaDAJBgcEAIvsQAECMFsGCysGAQQBpTQCgRYBMEwwSgYIKwYBBQUHAgEWPmh0dHA6Ly93d3cuZC10cnVzdC5uZXQvaW50ZXJuZXQvZmlsZXMvRC1UUlVTVF9Sb290X1BLSV9DUFMucGRmMIG+BgNVHR8EgbYwgbMwdKByoHCGbmxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDE2LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MDugOaA3hjVodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18yMDE2LmNybDAdBgNVHQ4EFgQU++3frUvwJbXSet2fmh0vbQlQIccwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwPQYJKoZIhvcNAQEKMDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMCAUADggIBAG030a1pW3Ze5g2lc2xNcDybRUNcCCe6tzzBYLZ2e4iM5MmwTjbUKfmLrJwsHLON5zCzcNqZQv9vubTEJ+BheP4n8KS2hvhSYsxeqyQCn+NCwounhvsHw9H8dF+yWsSN8ltMF33fYNRdI5ZYnO2oCGcqRb71MnK2lkVOXySYYMLi0P6+0NotCvlLsM0tuH50ahuDZk/1A+dVcATwLWB4LVvH3lP6FADCjMJ7Rq2lgGzJ60BAE/VuAi2FmS1XFOJOXHxUsE9auwOtlg0kUhI52ohrQ6KoJslB0Ze/v2ihMju2wY+85Vz5cKAt8rZRZcvJg8IN7AFOwoDvlp2/ejF7CXuIAf6BracK/hVsVMVVaeef4FwtXBrtIlZPQoMj369ZVBnPp0b5zwiYeVBjkQyZjBXTNwEQLZQc8fNN49GRVJV/FGjnd5XR6umz+GBjKXPcupPKVX2qoU5tviOr90xYHYTAo3mFJ+9HreVW2URl/GSJ/wN2Isk9RJlDwVqTpo8NoRPvutMfRyUkw/y297iGdRszmPfMjNQV9u6Nhv+7CzXcRHKsRK/LNN1F8jtMkFo7YCULYI5UK9staE/F+IKe04eBdo4D7bIIgb+zQ7RhgTvQdWtNu4cp1Opx+yJDHY/7k8yXtX5A5XcWuaQLn4vcx7lSs9YswY4998kMliPtWfpA"); + skOnlineOCSPSource.verifyOCSPResponse(basicOCSPResp); + Mockito.verify(skOnlineOCSPSource, Mockito.times(1)).verifyOcspResponderCertificate(any(), any()); + } + @Test public void dataLoaderMissing() { expectedException.expectMessage("Data loader is null"); diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/SkDataLoaderTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/SkDataLoaderTest.java index de93b2b42..03a71c912 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/SkDataLoaderTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/SkDataLoaderTest.java @@ -21,7 +21,6 @@ import org.digidoc4j.SignatureProfile; import org.digidoc4j.impl.asic.tsl.TslLoader; import org.digidoc4j.test.MockSkDataLoader; -import org.digidoc4j.test.TestAssert; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; @@ -39,8 +38,16 @@ public void ocspDataLoader_withProxyConfiguration() throws Exception { this.configuration.setHttpProxyHost("proxyHost"); this.configuration.setHttpProxyPort(1345); SkDataLoader dataLoader = new SkOCSPDataLoader(this.configuration); - TestAssert.assertHTTPProxyIsConfigured(dataLoader, "proxyHost", 1345); - TestAssert.assertProxyCredentialsAreUnset(dataLoader); + ProxyConfig config = dataLoader.getProxyConfig(); + Assert.assertNotNull(config); + ProxyProperties httpProperties = config.getHttpProperties(); + Assert.assertNotNull(httpProperties); + ProxyProperties httpsProperties = config.getHttpsProperties(); + Assert.assertNull(httpsProperties); + Assert.assertEquals("proxyHost", httpProperties.getHost()); + Assert.assertEquals(1345, httpProperties.getPort()); + Assert.assertNull(httpProperties.getUser()); + Assert.assertNull(httpProperties.getPassword()); } @Test @@ -50,14 +57,16 @@ public void dataLoader_withPasswordProxyConfiguration() throws Exception { this.configuration.setHttpProxyUser("proxyUser"); this.configuration.setHttpProxyPassword("proxyPassword"); SkDataLoader loader = new SkOCSPDataLoader(this.configuration); - TestAssert.assertHTTPProxyIsConfigured(loader, "proxyHost", 1345); ProxyConfig config = loader.getProxyConfig(); + Assert.assertNotNull(config); ProxyProperties httpProperties = config.getHttpProperties(); + Assert.assertNotNull(httpProperties); ProxyProperties httpsProperties = config.getHttpsProperties(); + Assert.assertNull(httpsProperties); + Assert.assertEquals("proxyHost", httpProperties.getHost()); + Assert.assertEquals(1345, httpProperties.getPort()); Assert.assertEquals("proxyUser", httpProperties.getUser()); - Assert.assertEquals("proxyUser", httpsProperties.getUser()); Assert.assertEquals("proxyPassword", httpProperties.getPassword()); - Assert.assertEquals("proxyPassword", httpsProperties.getPassword()); } @Test @@ -90,19 +99,19 @@ public void dataLoader_withoutSslConfiguration_shouldNotSetSslValues() throws Ex @Test public void dataLoader_withSslConfiguration_shouldSetSslValues() throws Exception { - this.configuration.setSslKeystorePath("classpath:testFiles/keystores/keystore.jks"); - this.configuration.setSslKeystoreType("keystore.type"); - this.configuration.setSslKeystorePassword("keystore.password"); + this.configuration.setSslKeystorePath("classpath:testFiles/keystores/keystore.p12"); + this.configuration.setSslKeystoreType("PKCS12"); + this.configuration.setSslKeystorePassword("keystore-password"); this.configuration.setSslTruststorePath("classpath:testFiles/keystores/truststore.jks"); - this.configuration.setSslTruststoreType("truststore.type"); - this.configuration.setSslTruststorePassword("truststore.password"); + this.configuration.setSslTruststoreType("JKS"); + this.configuration.setSslTruststorePassword("digidoc4j-password"); MockSkDataLoader dataLoader = new MockSkDataLoader(this.configuration); Assert.assertNotNull(dataLoader.getSslKeystore()); - Assert.assertEquals("keystore.type", dataLoader.getSslKeystoreType()); - Assert.assertEquals("keystore.password", dataLoader.getSslKeystorePassword()); + Assert.assertEquals("PKCS12", dataLoader.getSslKeystoreType()); + Assert.assertEquals("keystore-password", dataLoader.getSslKeystorePassword()); Assert.assertNotNull(dataLoader.getSslTruststore()); - Assert.assertEquals("truststore.type", dataLoader.getSslTruststoreType()); - Assert.assertEquals("truststore.password", dataLoader.getSslTruststorePassword()); + Assert.assertEquals("JKS", dataLoader.getSslTruststoreType()); + Assert.assertEquals("digidoc4j-password", dataLoader.getSslTruststorePassword()); Assert.assertTrue(dataLoader.isSslKeystoreTypeSet()); Assert.assertTrue(dataLoader.isSslKeystorePasswordSet()); Assert.assertTrue(dataLoader.isSslTruststoreTypeSet()); diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/StreamDocumentTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/StreamDocumentTest.java index 442c31ea2..c9fe9575c 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/StreamDocumentTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/StreamDocumentTest.java @@ -1,19 +1,34 @@ /* DigiDoc4J library -* -* This software is released under either the GNU Library General Public -* License (see LICENSE.LGPL). -* -* Note that the only valid version of the LGPL license as far as this -* project is concerned is the original GNU Library General Public License -* Version 2.1, February 1999 -*/ + * + * This software is released under either the GNU Library General Public + * License (see LICENSE.LGPL). + * + * Note that the only valid version of the LGPL license as far as this + * project is concerned is the original GNU Library General Public License + * Version 2.1, February 1999 + */ package org.digidoc4j.impl; +import eu.europa.esig.dss.enumerations.DigestAlgorithm; +import eu.europa.esig.dss.model.DSSException; +import eu.europa.esig.dss.model.MimeType; +import org.apache.commons.io.IOUtils; +import org.digidoc4j.AbstractTest; +import org.digidoc4j.DataFile; +import org.digidoc4j.test.MockStreamDocument; +import org.digidoc4j.utils.Helper; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; +import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -23,20 +38,6 @@ import java.util.HashSet; import java.util.Set; -import org.apache.commons.io.IOUtils; -import org.digidoc4j.AbstractTest; -import org.digidoc4j.DataFile; -import org.digidoc4j.test.MockStreamDocument; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import eu.europa.esig.dss.model.DSSException; -import eu.europa.esig.dss.enumerations.DigestAlgorithm; -import eu.europa.esig.dss.model.MimeType; - public class StreamDocumentTest extends AbstractTest { private static final Logger logger = LoggerFactory.getLogger(StreamDocumentTest.class); @@ -146,6 +147,19 @@ public void createDocumentFromStreamedDataFile() throws Exception { } } + @Test + public void documentManualDeletion() { + File dir = new File(System.getProperty("java.io.tmpdir")); + FilenameFilter filenameFilter = (dir1, name) -> name.toLowerCase().startsWith("digidoc4j") + && name.toLowerCase().endsWith(".tmp"); + Helper.deleteTmpFiles(10000000); + int count = dir.listFiles(filenameFilter).length; + Assert.assertTrue(count >= 1); + Helper.deleteTmpFiles(0); + count = dir.listFiles(filenameFilter).length; + Assert.assertEquals(0, count); + } + @Test public void getDigest() throws Exception { Assert.assertEquals("VZrq0IJk1XldOQlxjN0Fq9SVcuhP5VWQ7vMaiKCP3/0=", document.getDigest(DigestAlgorithm.SHA256)); diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/asic/DataLoaderDecoratorTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/DataLoaderDecoratorTest.java index 1078ff231..6529c2cb5 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/asic/DataLoaderDecoratorTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/DataLoaderDecoratorTest.java @@ -1,11 +1,10 @@ package org.digidoc4j.impl.asic; -import eu.europa.esig.dss.model.InMemoryDocument; import eu.europa.esig.dss.service.http.commons.CommonsDataLoader; import eu.europa.esig.dss.service.http.proxy.ProxyConfig; -import eu.europa.esig.dss.service.http.proxy.ProxyProperties; import org.digidoc4j.Configuration; import org.digidoc4j.ExternalConnectionType; +import org.digidoc4j.utils.KeyStoreDocument; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -21,7 +20,13 @@ @RunWith(MockitoJUnitRunner.class) public class DataLoaderDecoratorTest { private static final String KEYSTORE_PATH = "classpath:testFiles/keystores/keystore.jks"; - private static final String TRUSTSTORE_PATH = "classpath:testFiles/keystores/truststore.jks"; + private static final String TRUSTSTORE_PATH = "classpath:testFiles/keystores/truststore.p12"; + + private static final String KEYSTORE_TYPE = "JKS"; + private static final String TRUSTSTORE_TYPE = "PKCS12"; + + private static final String KEYSTORE_PASSWORD = "digidoc4j-password"; + private static final String TRUSTSTORE_PASSWORD = "truststore-password"; @Mock private Configuration configuration; @@ -33,7 +38,7 @@ public class DataLoaderDecoratorTest { public void decorateWithSslSettingsShouldDoNothingWhenSslConfigurationNotEnabled() { Mockito.doReturn(false).when(configuration).isSslConfigurationEnabled(); DataLoaderDecorator.decorateWithSslSettings(dataLoader, configuration); - Mockito.verifyZeroInteractions(dataLoader); + Mockito.verifyNoInteractions(dataLoader); } @Test @@ -42,7 +47,7 @@ public void decorateWithSslSettingsForShouldDoNothingWhenSslConfigurationNotEnab Mockito.doReturn(false).when(configuration).isSslConfigurationEnabled(); Mockito.doReturn(false).when(configuration).isSslConfigurationEnabledFor(connectionType); DataLoaderDecorator.decorateWithSslSettingsFor(connectionType, dataLoader, configuration); - Mockito.verifyZeroInteractions(dataLoader); + Mockito.verifyNoInteractions(dataLoader); Mockito.reset(configuration, dataLoader); } @@ -56,7 +61,7 @@ public void decorateWithSslSettingsShouldApplySslKeystorePathIfConfigured() { Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuites(); DataLoaderDecorator.decorateWithSslSettings(dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(InMemoryDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(KeyStoreDocument.class)); Mockito.verifyNoMoreInteractions(dataLoader); } @@ -69,7 +74,7 @@ public void decorateWithSslSettingsForShouldApplySslKeystorePathIfConfigured() { Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuitesFor(connectionType); DataLoaderDecorator.decorateWithSslSettingsFor(connectionType, dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(InMemoryDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(KeyStoreDocument.class)); Mockito.verifyNoMoreInteractions(dataLoader); Mockito.reset(configuration, dataLoader); @@ -80,15 +85,15 @@ public void decorateWithSslSettingsForShouldApplySslKeystorePathIfConfigured() { public void decorateWithSslSettingsShouldApplyAllSslKeystoreConfigurationIfPresent() { Mockito.doReturn(true).when(configuration).isSslConfigurationEnabled(); Mockito.doReturn(KEYSTORE_PATH).when(configuration).getSslKeystorePath(); - Mockito.doReturn("sslKeystoreType").when(configuration).getSslKeystoreType(); - Mockito.doReturn("sslKeystorePassword").when(configuration).getSslKeystorePassword(); + Mockito.doReturn(KEYSTORE_TYPE).when(configuration).getSslKeystoreType(); + Mockito.doReturn(KEYSTORE_PASSWORD).when(configuration).getSslKeystorePassword(); Mockito.doReturn(null).when(configuration).getSupportedSslProtocols(); Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuites(); DataLoaderDecorator.decorateWithSslSettings(dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType("sslKeystoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword("sslKeystorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType(KEYSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword(KEYSTORE_PASSWORD); Mockito.verifyNoMoreInteractions(dataLoader); } @@ -97,15 +102,15 @@ public void decorateWithSslSettingsForShouldApplyAllSslKeystoreConfigurationIfPr for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(true).when(configuration).isSslConfigurationEnabledFor(connectionType); Mockito.doReturn(KEYSTORE_PATH).when(configuration).getSslKeystorePathFor(connectionType); - Mockito.doReturn("sslKeystoreType").when(configuration).getSslKeystoreTypeFor(connectionType); - Mockito.doReturn("sslKeystorePassword").when(configuration).getSslKeystorePasswordFor(connectionType); + Mockito.doReturn(KEYSTORE_TYPE).when(configuration).getSslKeystoreTypeFor(connectionType); + Mockito.doReturn(KEYSTORE_PASSWORD).when(configuration).getSslKeystorePasswordFor(connectionType); Mockito.doReturn(null).when(configuration).getSupportedSslProtocolsFor(connectionType); Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuitesFor(connectionType); DataLoaderDecorator.decorateWithSslSettingsFor(connectionType, dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType("sslKeystoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword("sslKeystorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType(KEYSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword(KEYSTORE_PASSWORD); Mockito.verifyNoMoreInteractions(dataLoader); Mockito.reset(configuration, dataLoader); @@ -120,7 +125,7 @@ public void decorateWithSslSettingsShouldApplySslTruststorePathIfConfigured() { Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuites(); DataLoaderDecorator.decorateWithSslSettings(dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(InMemoryDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(KeyStoreDocument.class)); Mockito.verifyNoMoreInteractions(dataLoader); } @@ -133,7 +138,7 @@ public void decorateWithSslSettingsForShouldApplySslTruststorePathIfConfigured() Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuitesFor(connectionType); DataLoaderDecorator.decorateWithSslSettingsFor(connectionType, dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(InMemoryDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(KeyStoreDocument.class)); Mockito.verifyNoMoreInteractions(dataLoader); Mockito.reset(configuration, dataLoader); @@ -144,15 +149,15 @@ public void decorateWithSslSettingsForShouldApplySslTruststorePathIfConfigured() public void decorateWithSslSettingsShouldApplyAllSslTruststoreConfigurationIfPresent() { Mockito.doReturn(true).when(configuration).isSslConfigurationEnabled(); Mockito.doReturn(TRUSTSTORE_PATH).when(configuration).getSslTruststorePath(); - Mockito.doReturn("sslTruststoreType").when(configuration).getSslTruststoreType(); - Mockito.doReturn("sslTruststorePassword").when(configuration).getSslTruststorePassword(); + Mockito.doReturn(TRUSTSTORE_TYPE).when(configuration).getSslTruststoreType(); + Mockito.doReturn(TRUSTSTORE_PASSWORD).when(configuration).getSslTruststorePassword(); Mockito.doReturn(null).when(configuration).getSupportedSslProtocols(); Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuites(); DataLoaderDecorator.decorateWithSslSettings(dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType("sslTruststoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword("sslTruststorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType(TRUSTSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword(TRUSTSTORE_PASSWORD); Mockito.verifyNoMoreInteractions(dataLoader); } @@ -161,15 +166,15 @@ public void decorateWithSslSettingsForShouldApplyAllSslTruststoreConfigurationIf for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(true).when(configuration).isSslConfigurationEnabledFor(connectionType); Mockito.doReturn(TRUSTSTORE_PATH).when(configuration).getSslTruststorePathFor(connectionType); - Mockito.doReturn("sslTruststoreType").when(configuration).getSslTruststoreTypeFor(connectionType); - Mockito.doReturn("sslTruststorePassword").when(configuration).getSslTruststorePasswordFor(connectionType); + Mockito.doReturn(TRUSTSTORE_TYPE).when(configuration).getSslTruststoreTypeFor(connectionType); + Mockito.doReturn(TRUSTSTORE_PASSWORD).when(configuration).getSslTruststorePasswordFor(connectionType); Mockito.doReturn(null).when(configuration).getSupportedSslProtocolsFor(connectionType); Mockito.doReturn(null).when(configuration).getSupportedSslCipherSuitesFor(connectionType); DataLoaderDecorator.decorateWithSslSettingsFor(connectionType, dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType("sslTruststoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword("sslTruststorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType(TRUSTSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword(TRUSTSTORE_PASSWORD); Mockito.verifyNoMoreInteractions(dataLoader); Mockito.reset(configuration, dataLoader); @@ -244,23 +249,23 @@ public void decorateWithSslSettingsForShouldApplySupportedSslCipherSuitesIfConfi public void decorateWithSslSettingsShouldApplyAllConfiguredSslProperties() { Mockito.doReturn(true).when(configuration).isSslConfigurationEnabled(); Mockito.doReturn(KEYSTORE_PATH).when(configuration).getSslKeystorePath(); - Mockito.doReturn("sslKeystoreType").when(configuration).getSslKeystoreType(); - Mockito.doReturn("sslKeystorePassword").when(configuration).getSslKeystorePassword(); + Mockito.doReturn(KEYSTORE_TYPE).when(configuration).getSslKeystoreType(); + Mockito.doReturn(KEYSTORE_PASSWORD).when(configuration).getSslKeystorePassword(); Mockito.doReturn(TRUSTSTORE_PATH).when(configuration).getSslTruststorePath(); - Mockito.doReturn("sslTruststoreType").when(configuration).getSslTruststoreType(); - Mockito.doReturn("sslTruststorePassword").when(configuration).getSslTruststorePassword(); + Mockito.doReturn(TRUSTSTORE_TYPE).when(configuration).getSslTruststoreType(); + Mockito.doReturn(TRUSTSTORE_PASSWORD).when(configuration).getSslTruststorePassword(); Mockito.doReturn(Arrays.asList("sslProtocol1", "sslProtocol2")).when(configuration).getSupportedSslProtocols(); Mockito.doReturn(Arrays.asList("sslCipherSuite1", "sslCipherSuite2")).when(configuration).getSupportedSslCipherSuites(); DataLoaderDecorator.decorateWithSslSettings(dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType("sslKeystoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword("sslKeystorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType(KEYSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword(KEYSTORE_PASSWORD); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType("sslTruststoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword("sslTruststorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType(TRUSTSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword(TRUSTSTORE_PASSWORD); ArgumentCaptor protocolsCaptor = ArgumentCaptor.forClass(String[].class); Mockito.verify(dataLoader, Mockito.times(1)).setSupportedSSLProtocols(protocolsCaptor.capture()); @@ -278,23 +283,23 @@ public void decorateWithSslSettingsForShouldApplyAllConfiguredSslProperties() { for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(true).when(configuration).isSslConfigurationEnabledFor(connectionType); Mockito.doReturn(KEYSTORE_PATH).when(configuration).getSslKeystorePathFor(connectionType); - Mockito.doReturn("sslKeystoreType").when(configuration).getSslKeystoreTypeFor(connectionType); - Mockito.doReturn("sslKeystorePassword").when(configuration).getSslKeystorePasswordFor(connectionType); + Mockito.doReturn(KEYSTORE_TYPE).when(configuration).getSslKeystoreTypeFor(connectionType); + Mockito.doReturn(KEYSTORE_PASSWORD).when(configuration).getSslKeystorePasswordFor(connectionType); Mockito.doReturn(TRUSTSTORE_PATH).when(configuration).getSslTruststorePathFor(connectionType); - Mockito.doReturn("sslTruststoreType").when(configuration).getSslTruststoreTypeFor(connectionType); - Mockito.doReturn("sslTruststorePassword").when(configuration).getSslTruststorePasswordFor(connectionType); + Mockito.doReturn(TRUSTSTORE_TYPE).when(configuration).getSslTruststoreTypeFor(connectionType); + Mockito.doReturn(TRUSTSTORE_PASSWORD).when(configuration).getSslTruststorePasswordFor(connectionType); Mockito.doReturn(Arrays.asList("sslProtocol1", "sslProtocol2")).when(configuration).getSupportedSslProtocolsFor(connectionType); Mockito.doReturn(Arrays.asList("sslCipherSuite1", "sslCipherSuite2")).when(configuration).getSupportedSslCipherSuitesFor(connectionType); DataLoaderDecorator.decorateWithSslSettingsFor(connectionType, dataLoader, configuration); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType("sslKeystoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword("sslKeystorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystoreType(KEYSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslKeystorePassword(KEYSTORE_PASSWORD); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(InMemoryDocument.class)); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType("sslTruststoreType"); - Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword("sslTruststorePassword"); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststore(any(KeyStoreDocument.class)); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststoreType(TRUSTSTORE_TYPE); + Mockito.verify(dataLoader, Mockito.times(1)).setSslTruststorePassword(TRUSTSTORE_PASSWORD); ArgumentCaptor protocolsCaptor = ArgumentCaptor.forClass(String[].class); Mockito.verify(dataLoader, Mockito.times(1)).setSupportedSSLProtocols(protocolsCaptor.capture()); @@ -313,7 +318,7 @@ public void decorateWithSslSettingsForShouldApplyAllConfiguredSslProperties() { public void decorateWithProxySettingsShouldDoNothingWhenNetworkProxyNotEnabled() { Mockito.doReturn(false).when(configuration).isNetworkProxyEnabled(); DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); - Mockito.verifyZeroInteractions(dataLoader); + Mockito.verifyNoInteractions(dataLoader); } @Test @@ -321,7 +326,71 @@ public void decorateWithProxySettingsForShouldDoNothingWhenNetworkProxyNotEnable for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(false).when(configuration).isNetworkProxyEnabledFor(connectionType); DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); - Mockito.verifyZeroInteractions(dataLoader); + Mockito.verifyNoInteractions(dataLoader); + + Mockito.reset(configuration, dataLoader); + } + } + + @Test + public void decorateWithProxySettingsShouldApplyNullConfigIfHostIsNotConfigured() { + Mockito.doReturn(true).when(configuration).isNetworkProxyEnabled(); + Mockito.doReturn(8073).when(configuration).getHttpProxyPort(); + Mockito.doReturn(473).when(configuration).getHttpsProxyPort(); + Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUser(); + Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPassword(); + + DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); + ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNull(capturedProxyConfig); + } + + @Test + public void decorateWithProxySettingsForShouldApplyNullConfigIfHostIsNotConfigured() { + for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { + Mockito.doReturn(true).when(configuration).isNetworkProxyEnabledFor(connectionType); + Mockito.doReturn(8073).when(configuration).getHttpProxyPortFor(connectionType); + Mockito.doReturn(473).when(configuration).getHttpsProxyPortFor(connectionType); + Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUserFor(connectionType); + Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPasswordFor(connectionType); + + DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); + ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNull(capturedProxyConfig); + + Mockito.reset(configuration, dataLoader); + } + } + + @Test + public void decorateWithProxySettingsShouldApplyNullConfigIfPortIsNotConfigured() { + Mockito.doReturn(true).when(configuration).isNetworkProxyEnabled(); + Mockito.doReturn(null).when(configuration).getHttpProxyPort(); + Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHost(); + Mockito.doReturn(null).when(configuration).getHttpsProxyPort(); + Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHost(); + Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUser(); + Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPassword(); + + DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); + ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNull(capturedProxyConfig); + } + + @Test + public void decorateWithProxySettingsForShouldApplyNullConfigIfPortIsNotConfigured() { + for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { + Mockito.doReturn(true).when(configuration).isNetworkProxyEnabledFor(connectionType); + Mockito.doReturn(null).when(configuration).getHttpProxyPortFor(connectionType); + Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHostFor(connectionType); + Mockito.doReturn(null).when(configuration).getHttpsProxyPortFor(connectionType); + Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHostFor(connectionType); + Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUserFor(connectionType); + Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPasswordFor(connectionType); + + DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); + ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNull(capturedProxyConfig); Mockito.reset(configuration, dataLoader); } @@ -330,12 +399,13 @@ public void decorateWithProxySettingsForShouldDoNothingWhenNetworkProxyNotEnable @Test public void decorateWithProxySettingsShouldApplyHttpHostAndPortIfConfigured() { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabled(); - Mockito.doReturn(Integer.valueOf(8073)).when(configuration).getHttpProxyPort(); + Mockito.doReturn(8073).when(configuration).getHttpProxyPort(); Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHost(); DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); - assertProxyPropertiesNotConfigured(capturedProxyConfig.getHttpsProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNull(capturedProxyConfig.getHttpsProperties()); Assert.assertEquals(8073, capturedProxyConfig.getHttpProperties().getPort()); Assert.assertEquals("httpProxyHost", capturedProxyConfig.getHttpProperties().getHost()); @@ -348,12 +418,13 @@ public void decorateWithProxySettingsShouldApplyHttpHostAndPortIfConfigured() { public void decorateWithProxySettingsForShouldApplyHttpHostAndPortIfConfigured() { for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabledFor(connectionType); - Mockito.doReturn(Integer.valueOf(8073)).when(configuration).getHttpProxyPortFor(connectionType); + Mockito.doReturn(8073).when(configuration).getHttpProxyPortFor(connectionType); Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHostFor(connectionType); DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); - assertProxyPropertiesNotConfigured(capturedProxyConfig.getHttpsProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNull(capturedProxyConfig.getHttpsProperties()); Assert.assertEquals(8073, capturedProxyConfig.getHttpProperties().getPort()); Assert.assertEquals("httpProxyHost", capturedProxyConfig.getHttpProperties().getHost()); @@ -368,12 +439,13 @@ public void decorateWithProxySettingsForShouldApplyHttpHostAndPortIfConfigured() @Test public void decorateWithProxySettingsShouldApplyHttpsHostAndPortIfConfigured() { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabled(); - Mockito.doReturn(Integer.valueOf(473)).when(configuration).getHttpsProxyPort(); + Mockito.doReturn(473).when(configuration).getHttpsProxyPort(); Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHost(); DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); - assertProxyPropertiesNotConfigured(capturedProxyConfig.getHttpProperties()); + Assert.assertNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpsProperties()); Assert.assertEquals(473, capturedProxyConfig.getHttpsProperties().getPort()); Assert.assertEquals("httpsProxyHost", capturedProxyConfig.getHttpsProperties().getHost()); @@ -386,12 +458,13 @@ public void decorateWithProxySettingsShouldApplyHttpsHostAndPortIfConfigured() { public void decorateWithProxySettingsForShouldApplyHttpsHostAndPortIfConfigured() { for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabledFor(connectionType); - Mockito.doReturn(Integer.valueOf(473)).when(configuration).getHttpsProxyPortFor(connectionType); + Mockito.doReturn(473).when(configuration).getHttpsProxyPortFor(connectionType); Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHostFor(connectionType); DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); - assertProxyPropertiesNotConfigured(capturedProxyConfig.getHttpProperties()); + Assert.assertNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpsProperties()); Assert.assertEquals(473, capturedProxyConfig.getHttpsProperties().getPort()); Assert.assertEquals("httpsProxyHost", capturedProxyConfig.getHttpsProperties().getHost()); @@ -404,45 +477,85 @@ public void decorateWithProxySettingsForShouldApplyHttpsHostAndPortIfConfigured( } @Test - public void decorateWithProxySettingsShouldApplyUserAndPasswordIfConfigured() { + public void decorateWithProxySettingsShouldApplyHttpUserAndPasswordIfConfigured() { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabled(); + Mockito.doReturn(8073).when(configuration).getHttpProxyPort(); + Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHost(); Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUser(); Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPassword(); DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNotNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNull(capturedProxyConfig.getHttpsProperties()); - Assert.assertEquals(0, capturedProxyConfig.getHttpProperties().getPort()); - Assert.assertNull(capturedProxyConfig.getHttpProperties().getHost()); + Assert.assertEquals(8073, capturedProxyConfig.getHttpProperties().getPort()); + Assert.assertEquals("httpProxyHost", capturedProxyConfig.getHttpProperties().getHost()); Assert.assertNull(capturedProxyConfig.getHttpProperties().getExcludedHosts()); Assert.assertEquals("proxyUser", capturedProxyConfig.getHttpProperties().getUser()); Assert.assertEquals("proxyPassword", capturedProxyConfig.getHttpProperties().getPassword()); - - Assert.assertEquals(0, capturedProxyConfig.getHttpsProperties().getPort()); - Assert.assertNull(capturedProxyConfig.getHttpsProperties().getHost()); - Assert.assertNull(capturedProxyConfig.getHttpsProperties().getExcludedHosts()); - Assert.assertEquals("proxyUser", capturedProxyConfig.getHttpsProperties().getUser()); - Assert.assertEquals("proxyPassword", capturedProxyConfig.getHttpsProperties().getPassword()); } @Test - public void decorateWithProxySettingsForShouldApplyUserAndPasswordIfConfigured() { + public void decorateWithProxySettingsForShouldApplyHttpUserAndPasswordIfConfigured() { for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabledFor(connectionType); + Mockito.doReturn(8073).when(configuration).getHttpProxyPortFor(connectionType); + Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHostFor(connectionType); Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUserFor(connectionType); Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPasswordFor(connectionType); DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNotNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNull(capturedProxyConfig.getHttpsProperties()); - Assert.assertEquals(0, capturedProxyConfig.getHttpProperties().getPort()); - Assert.assertNull(capturedProxyConfig.getHttpProperties().getHost()); + Assert.assertEquals(8073, capturedProxyConfig.getHttpProperties().getPort()); + Assert.assertEquals("httpProxyHost", capturedProxyConfig.getHttpProperties().getHost()); Assert.assertNull(capturedProxyConfig.getHttpProperties().getExcludedHosts()); Assert.assertEquals("proxyUser", capturedProxyConfig.getHttpProperties().getUser()); Assert.assertEquals("proxyPassword", capturedProxyConfig.getHttpProperties().getPassword()); - Assert.assertEquals(0, capturedProxyConfig.getHttpsProperties().getPort()); - Assert.assertNull(capturedProxyConfig.getHttpsProperties().getHost()); + Mockito.reset(configuration, dataLoader); + } + } + + @Test + public void decorateWithProxySettingsShouldApplyHttpsUserAndPasswordIfConfigured() { + Mockito.doReturn(true).when(configuration).isNetworkProxyEnabled(); + Mockito.doReturn(473).when(configuration).getHttpsProxyPort(); + Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHost(); + Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUser(); + Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPassword(); + + DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); + ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpsProperties()); + + Assert.assertEquals(473, capturedProxyConfig.getHttpsProperties().getPort()); + Assert.assertEquals("httpsProxyHost", capturedProxyConfig.getHttpsProperties().getHost()); + Assert.assertNull(capturedProxyConfig.getHttpsProperties().getExcludedHosts()); + Assert.assertEquals("proxyUser", capturedProxyConfig.getHttpsProperties().getUser()); + Assert.assertEquals("proxyPassword", capturedProxyConfig.getHttpsProperties().getPassword()); + } + + @Test + public void decorateWithProxySettingsForShouldApplyHttpsUserAndPasswordIfConfigured() { + for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { + Mockito.doReturn(true).when(configuration).isNetworkProxyEnabledFor(connectionType); + Mockito.doReturn(473).when(configuration).getHttpsProxyPortFor(connectionType); + Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHostFor(connectionType); + Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUserFor(connectionType); + Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPasswordFor(connectionType); + + DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); + ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpsProperties()); + + Assert.assertEquals(473, capturedProxyConfig.getHttpsProperties().getPort()); + Assert.assertEquals("httpsProxyHost", capturedProxyConfig.getHttpsProperties().getHost()); Assert.assertNull(capturedProxyConfig.getHttpsProperties().getExcludedHosts()); Assert.assertEquals("proxyUser", capturedProxyConfig.getHttpsProperties().getUser()); Assert.assertEquals("proxyPassword", capturedProxyConfig.getHttpsProperties().getPassword()); @@ -454,15 +567,17 @@ public void decorateWithProxySettingsForShouldApplyUserAndPasswordIfConfigured() @Test public void decorateWithProxySettingsShouldApplyAllConfiguredProxySettings() { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabled(); - Mockito.doReturn(Integer.valueOf(8073)).when(configuration).getHttpProxyPort(); + Mockito.doReturn(8073).when(configuration).getHttpProxyPort(); Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHost(); - Mockito.doReturn(Integer.valueOf(473)).when(configuration).getHttpsProxyPort(); + Mockito.doReturn(473).when(configuration).getHttpsProxyPort(); Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHost(); Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUser(); Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPassword(); DataLoaderDecorator.decorateWithProxySettings(dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNotNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpsProperties()); Assert.assertEquals(8073, capturedProxyConfig.getHttpProperties().getPort()); Assert.assertEquals("httpProxyHost", capturedProxyConfig.getHttpProperties().getHost()); @@ -481,15 +596,17 @@ public void decorateWithProxySettingsShouldApplyAllConfiguredProxySettings() { public void decorateWithProxySettingsForShouldApplyAllConfiguredProxySettings() { for (final ExternalConnectionType connectionType : ExternalConnectionType.values()) { Mockito.doReturn(true).when(configuration).isNetworkProxyEnabledFor(connectionType); - Mockito.doReturn(Integer.valueOf(8073)).when(configuration).getHttpProxyPortFor(connectionType); + Mockito.doReturn(8073).when(configuration).getHttpProxyPortFor(connectionType); Mockito.doReturn("httpProxyHost").when(configuration).getHttpProxyHostFor(connectionType); - Mockito.doReturn(Integer.valueOf(473)).when(configuration).getHttpsProxyPortFor(connectionType); + Mockito.doReturn(473).when(configuration).getHttpsProxyPortFor(connectionType); Mockito.doReturn("httpsProxyHost").when(configuration).getHttpsProxyHostFor(connectionType); Mockito.doReturn("proxyUser").when(configuration).getHttpProxyUserFor(connectionType); Mockito.doReturn("proxyPassword").when(configuration).getHttpProxyPasswordFor(connectionType); DataLoaderDecorator.decorateWithProxySettingsFor(connectionType, dataLoader, configuration); ProxyConfig capturedProxyConfig = verifyDataLoaderProxyConfigSetAndCaptureProxyConfig(); + Assert.assertNotNull(capturedProxyConfig.getHttpProperties()); + Assert.assertNotNull(capturedProxyConfig.getHttpsProperties()); Assert.assertEquals(8073, capturedProxyConfig.getHttpProperties().getPort()); Assert.assertEquals("httpProxyHost", capturedProxyConfig.getHttpProperties().getHost()); @@ -514,12 +631,4 @@ private ProxyConfig verifyDataLoaderProxyConfigSetAndCaptureProxyConfig() { return argumentCaptor.getValue(); } - private void assertProxyPropertiesNotConfigured(ProxyProperties proxyProperties) { - Assert.assertEquals(0, proxyProperties.getPort()); - Assert.assertNull(proxyProperties.getExcludedHosts()); - Assert.assertNull(proxyProperties.getHost()); - Assert.assertNull(proxyProperties.getUser()); - Assert.assertNull(proxyProperties.getPassword()); - } - } \ No newline at end of file diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/asic/EmptyDataFilesContainerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/EmptyDataFilesContainerTest.java new file mode 100644 index 000000000..0894826b8 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/EmptyDataFilesContainerTest.java @@ -0,0 +1,85 @@ +package org.digidoc4j.impl.asic; + +import org.digidoc4j.AbstractTest; +import org.digidoc4j.Container; +import org.digidoc4j.DataFile; +import org.digidoc4j.exceptions.InvalidDataFileException; +import org.junit.Assert; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +public abstract class EmptyDataFilesContainerTest extends AbstractTest { + + protected static final String TEST_FILE_NAME = "test.txt"; + protected static final String TEST_FILE_MIMETYPE = "text/plain"; + protected static final String EMPTY_FILE_PATH = "src/test/resources/testFiles/helper-files/empty.txt"; + + protected static final String DATAFILES_CANNOT_BE_EMPTY_MESSAGE = "Datafiles cannot be empty"; + + protected abstract Container.DocumentType getDocumentType(); + + @Test + public void testAddEmptyDataFileFromPath() { + Container container = createEmptyContainerBy(getDocumentType()); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> container.addDataFile(EMPTY_FILE_PATH, TEST_FILE_MIMETYPE) + ); + + Assert.assertEquals(DATAFILES_CANNOT_BE_EMPTY_MESSAGE, caughtException.getMessage()); + Assert.assertEquals(0, container.getDataFiles().size()); + } + + @Test + public void testAddEmptyDataFileFromStream() { + Container container = createEmptyContainerBy(getDocumentType()); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> { + try (InputStream inputStream = new ByteArrayInputStream(new byte[0])) { + container.addDataFile(inputStream, TEST_FILE_NAME, TEST_FILE_MIMETYPE); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + ); + + Assert.assertEquals(DATAFILES_CANNOT_BE_EMPTY_MESSAGE, caughtException.getMessage()); + Assert.assertEquals(0, container.getDataFiles().size()); + } + + @Test + public void testAddEmptyDataFileFromFile() { + Container container = createEmptyContainerBy(getDocumentType()); + File emptyFile = new File(EMPTY_FILE_PATH); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> container.addDataFile(emptyFile, TEST_FILE_MIMETYPE) + ); + + Assert.assertEquals(DATAFILES_CANNOT_BE_EMPTY_MESSAGE, caughtException.getMessage()); + Assert.assertEquals(0, container.getDataFiles().size()); + } + + @Test + public void testAddEmptyDataFile() { + Container container = createEmptyContainerBy(getDocumentType()); + DataFile emptyDataFile = new DataFile(new byte[0], TEST_FILE_NAME, TEST_FILE_MIMETYPE); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> container.addDataFile(emptyDataFile) + ); + + Assert.assertEquals(DATAFILES_CANNOT_BE_EMPTY_MESSAGE, caughtException.getMessage()); + Assert.assertEquals(0, container.getDataFiles().size()); + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/asic/EntryValidatorTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/EntryValidatorTest.java new file mode 100644 index 000000000..11dd96cc0 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/EntryValidatorTest.java @@ -0,0 +1,54 @@ +package org.digidoc4j.impl.asic; + +import org.digidoc4j.Configuration; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class EntryValidatorTest { + + @Test(expected = Test.None.class) + public void emptyInput() throws IOException { + ByteArrayInputStream inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + AsicStreamContainerParser containerParser = new AsicStreamContainerParser(inputStream, Configuration.of(Configuration.Mode.TEST)); + containerParser.parseContainer(); + AsicStreamContainerParser.EntryValidator validator = containerParser.new EntryValidator(); + validator.validate(0); + } + + @Test(expected = IOException.class) + public void emptyZipEntriesAndBigInput() throws IOException { + ByteArrayInputStream inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + AsicStreamContainerParser containerParser = new AsicStreamContainerParser(inputStream, Configuration.of(Configuration.Mode.TEST)); + AsicStreamContainerParser.EntryValidator validator = containerParser.new EntryValidator(); + validator.validate(1000001); + } + + @Test(expected = Test.None.class) + public void potentialBloatingButNotExceedingMinimumThreshold() throws IOException { + ByteArrayInputStream inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + AsicStreamContainerParser containerParser = new AsicStreamContainerParser(inputStream, Configuration.of(Configuration.Mode.TEST)); + AsicStreamContainerParser.EntryValidator validator = containerParser.new EntryValidator(); + validator.validate(1000000); + } + + @Test(expected = Test.None.class) + public void normalZipContainer() throws IOException { + FileInputStream inputStream = new FileInputStream("src/test/resources/testFiles/valid-containers/valid-asice.asice"); + AsicStreamContainerParser containerParser = new AsicStreamContainerParser(inputStream, Configuration.of(Configuration.Mode.TEST)); + containerParser.parseContainer(); + } + + @Test(expected = IOException.class) + public void unCompressedInputTooBig() throws IOException { + FileInputStream inputStream = new FileInputStream("src/test/resources/testFiles/valid-containers/valid-asice.asice"); + AsicStreamContainerParser containerParser = new AsicStreamContainerParser(inputStream, Configuration.of(Configuration.Mode.TEST)); + containerParser.parseContainer(); + AsicStreamContainerParser.EntryValidator validator = containerParser.new EntryValidator(); + validator.validate(1000001); + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/asic/tsl/TslDataLoaderFactoryTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/tsl/TslDataLoaderFactoryTest.java index fc60dac6a..7d2261f6b 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/asic/tsl/TslDataLoaderFactoryTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/asic/tsl/TslDataLoaderFactoryTest.java @@ -64,8 +64,8 @@ public void testDefaultFileCacheDataLoaderWithProxyConfigCreatedWhenNoCustomData public void testDefaultFileCacheDataLoaderWithSslConfigCreatedWhenNoCustomDataLoaderFactoryConfiguredAndTslLocationIsHttpUrl() { configuration.setTslLocation("http://tsl.host:8080/path"); configuration.setSslTruststorePath("classpath:testFiles/truststores/empty-truststore.p12"); - configuration.setSslTruststorePassword("ssl-truststore-password"); - configuration.setSslTruststoreType("SSL_TRUSTSTORE_TYPE"); + configuration.setSslTruststorePassword("digidoc4j-password"); + configuration.setSslTruststoreType("PKCS12"); configuration.setSupportedSslCipherSuites(Arrays.asList("supported_cipher_suite")); configuration.setSupportedSslProtocols(Arrays.asList("supported_ssl_protocol")); diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/BDocContainerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/BDocContainerTest.java index 5b70a90ca..339ee216d 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/BDocContainerTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/BDocContainerTest.java @@ -71,25 +71,25 @@ public class BDocContainerTest extends AbstractTest { @Test public void testSetDigestAlgorithmToSHA256() throws Exception { - AsicESignature signature = this.createSignatureBy(DigestAlgorithm.SHA256, this.pkcs12SignatureToken); + AsicESignature signature = this.createSignatureBy(DigestAlgorithm.SHA256, pkcs12SignatureToken); Assert.assertEquals("http://www.w3.org/2001/04/xmlenc#sha256", signature.getSignatureDigestAlgorithm().getUri()); } @Test public void testSetDigestAlgorithmToSHA1() throws Exception { - AsicESignature signature = this.createSignatureBy(DigestAlgorithm.SHA1, this.pkcs12SignatureToken); + AsicESignature signature = this.createSignatureBy(DigestAlgorithm.SHA1, pkcs12SignatureToken); Assert.assertEquals("http://www.w3.org/2000/09/xmldsig#sha1", signature.getSignatureDigestAlgorithm().getUri()); } @Test public void testSetDigestAlgorithmToSHA224() throws Exception { - AsicESignature signature = this.createSignatureBy(DigestAlgorithm.SHA224, this.pkcs12SignatureToken); + AsicESignature signature = this.createSignatureBy(DigestAlgorithm.SHA224, pkcs12SignatureToken); Assert.assertEquals("http://www.w3.org/2001/04/xmldsig-more#sha224", signature.getSignatureDigestAlgorithm().getUri()); } @Test public void testDefaultDigestAlgorithm() throws Exception { - AsicESignature signature = this.createSignatureBy(Container.DocumentType.BDOC, this.pkcs12SignatureToken); + AsicESignature signature = this.createSignatureBy(Container.DocumentType.BDOC, pkcs12SignatureToken); Assert.assertEquals("http://www.w3.org/2001/04/xmlenc#sha256", signature.getSignatureDigestAlgorithm().getUri()); } @@ -119,7 +119,7 @@ public int read() throws IOException { } @Override - public int read(byte b[], int off, int len) throws IOException { + public int read(byte[] b, int off, int len) throws IOException { throw new IOException(); } @@ -139,7 +139,7 @@ public void testAddRawSignature() throws Exception { @Test public void testAddUnknownFileTypeKeepsMimeType() { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.unknown_type"), "text/test_type"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -149,20 +149,20 @@ public void testAddUnknownFileTypeKeepsMimeType() { @Test public void testSaveBDocDocumentWithTwoSignatures() throws Exception { Container container = this.createNonEmptyContainerBy(Container.DocumentType.BDOC); - this.createSignatureBy(container, this.pkcs12SignatureToken); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); Assert.assertEquals(2, container.getSignatures().size()); - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", container.getSignatures().get(0).getSigningCertificate().getSerial()); - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", container.getSignatures().get(1).getSigningCertificate().getSerial()); container = ContainerOpener.open(file); Assert.assertEquals(2, container.getSignatures().size()); - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", container.getSignatures().get(0).getSigningCertificate().getSerial()); - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", container.getSignatures().get(1).getSigningCertificate().getSerial()); } @@ -209,7 +209,7 @@ public void openContainerWithoutSignatures_addDataFileAndSignContainer() throws Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/container_without_signatures.bdoc"); Assert.assertEquals(1, container.getDataFiles().size()); container.addDataFile("src/test/resources/testFiles/helper-files/test.xml", "text/xml"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Assert.assertEquals(1, container.getSignatures().size()); Assert.assertTrue(container.validate().isValid()); String file = this.getFileBy("bdoc"); @@ -221,7 +221,7 @@ public void openContainerWithoutSignatures_addDataFileAndSignContainer() throws @Test public void testGetDefaultSignatureParameters() { Container container = this.createNonEmptyContainerBy(Container.DocumentType.BDOC); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -236,22 +236,22 @@ public void testGetDefaultSignatureParameters() { @Test public void getSignatureByIndex() { Container container = this.createNonEmptyContainerBy(Container.DocumentType.BDOC); - this.createSignatureBy(container, this.pkcs12SignatureToken); - this.createSignatureBy(container, this.pkcs12SignatureToken); - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", container.getSignatures().get(1).getSigningCertificate().getSerial()); + this.createSignatureBy(container, pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", container.getSignatures().get(1).getSigningCertificate().getSerial()); } @Test public void notThrowingNPEWhenDOCXFileIsAddedToContainer() { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/word_file.docx"), "text/xml"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Assert.assertEquals(1, container.getSignatures().size()); } @Test public void signPdfDataFile() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/special-char-files/dds_acrobat.pdf"), "application/pdf"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Assert.assertEquals(1, container.getDataFiles().size()); Assert.assertEquals(1, container.getSignatures().size()); String file = this.getFileBy("bdoc"); @@ -264,15 +264,15 @@ public void signPdfDataFile() throws Exception { @Test public void testAddSignaturesToExistingDocument() throws Exception { Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/asics_testing_two_signatures.bdoc"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); Assert.assertEquals(3, container.getSignatures().size()); - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", container.getSignatures().get(2).getSigningCertificate().getSerial()); container = ContainerOpener.open(file); Assert.assertEquals(3, container.getSignatures().size()); - Assert.assertEquals("530be41bbc597c44570e2b7c13bcfa0c", + Assert.assertEquals("6ec00b8b8c54c4f76082bd843e3a1526", container.getSignatures().get(2).getSigningCertificate().getSerial()); Assert.assertEquals(0, container.validate().getErrors().size()); } @@ -280,7 +280,7 @@ public void testAddSignaturesToExistingDocument() throws Exception { @Test public void testRemoveSignatureWhenOneSignatureExists() throws Exception { Container container = this.createNonEmptyContainerBy(Container.DocumentType.BDOC); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Signature signature = container.getSignatures().get(0); container.removeSignature(signature); String file = this.getFileBy("bdoc"); @@ -294,7 +294,7 @@ public void testRemoveSignatureWhenOneSignatureExists() throws Exception { public void testAddFilesWithSpecialCharactersIntoContainer() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/special-char-files/dds_dds_JÜRIÖÖ € žŠ päev.txt"), "text/plain"); //container.addDataFile("src/test/resources/testFiles/special-char-files/dds_колючей стерне.docx", "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); container.saveAsFile(this.getFileBy("bdoc")); Assert.assertEquals(0, container.validate().getContainerErrors().size()); } @@ -314,7 +314,7 @@ public void testRemoveSignatureWhenTwoSignaturesExist() throws Exception { @Test public void testRemoveSignatureWhenThreeSignaturesExist() throws Exception { Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/asics_testing_two_signatures.bdoc"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -331,7 +331,7 @@ public void testRemoveSignatureWhenThreeSignaturesExist() throws Exception { public void removeNewlyAddedSignatureFromExistingContainer() throws Exception { Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/asics_testing_two_signatures.bdoc"); Assert.assertEquals(2, container.getSignatures().size()); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Assert.assertEquals(3, container.getSignatures().size()); container.removeSignature(container.getSignatures().get(0)); Assert.assertEquals(2, container.getSignatures().size()); @@ -437,7 +437,7 @@ public void testAddingSameFileSeveralTimesViaInputStream() throws Exception { public void testAddDateFileViaInputStream() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile(new ByteArrayInputStream("test".getBytes()), "src/test/resources/testFiles/helper-files/test.txt", "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Assert.assertTrue(container.validate().isValid()); } @@ -445,7 +445,7 @@ public void testAddDateFileViaInputStream() throws Exception { public void testAddingSameFileInDifferentContainerSeveralTimes() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); container.save(this.getFileBy("bdoc")); } @@ -459,7 +459,7 @@ public void testAddFileAsStream() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); ByteArrayInputStream stream = new ByteArrayInputStream("tere, tere".getBytes()); container.addDataFile(stream, "test1.txt", "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); Container containerToTest = ContainerOpener.open(file); @@ -470,10 +470,10 @@ public void testAddFileAsStream() throws Exception { public void setsSignatureId() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); Signature signature1 = SignatureBuilder.aSignature(container).withSignatureId("SIGNATURE-1"). - withSignatureToken(this.pkcs12SignatureToken).invokeSigning(); + withSignatureToken(pkcs12SignatureToken).invokeSigning(); container.addSignature(signature1); Signature signature2 = SignatureBuilder.aSignature(container).withSignatureId("SIGNATURE-2"). - withSignatureToken(this.pkcs12SignatureToken).invokeSigning(); + withSignatureToken(pkcs12SignatureToken).invokeSigning(); container.addSignature(signature2); String file = this.getFileBy("bdoc"); container.saveAsFile(file); @@ -488,8 +488,8 @@ public void setsSignatureId() throws Exception { @Test public void setsDefaultSignatureId() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -506,7 +506,7 @@ public void setsDefaultSignatureId() throws Exception { @Test public void getDataFileByIndex() { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Assert.assertEquals("test.txt", container.getDataFile(0).getName()); } @@ -528,7 +528,7 @@ public void testLargeFileSigning() throws Exception { .withConfiguration(new Configuration(Configuration.Mode.TEST)).build(); container.getConfiguration().enableBigFilesSupport(10); container.addDataFile(this.createNonEmptyLargeContainer(container.getConfiguration().getMaxDataFileCachedInBytes() + 100), "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); } @Test @@ -538,7 +538,7 @@ public void openLargeFileFromStream() throws IOException { container.getConfiguration().enableBigFilesSupport(0); String file = this.createNonEmptyLargeContainer(container.getConfiguration().getMaxDataFileCachedInBytes() + 100); container.addDataFile(file, "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); container.save(file); try (FileInputStream stream = new FileInputStream(new File(file))) { ContainerOpener.open(stream, true); @@ -553,7 +553,7 @@ public void openAddFileFromStream() throws IOException { String file = this.createNonEmptyLargeContainer(container.getConfiguration().getMaxDataFileCachedInBytes() + 100); try (FileInputStream stream = new FileInputStream(new File(file))) { container.addDataFile(stream, "fileName", "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); container.save(file); FileInputStream stream2 = new FileInputStream(new File(file)); ContainerOpener.open(stream2, true); @@ -572,7 +572,9 @@ public void testGetDocumentType() throws Exception { public void testAddTwoFilesAsStream() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); ByteArrayInputStream stream = new ByteArrayInputStream("tere, tere".getBytes()); + stream.mark(Integer.MAX_VALUE); container.addDataFile(stream, "test1.txt", "text/plain"); + stream.reset(); container.addDataFile(stream, "test2.txt", "text/plain"); } @@ -581,7 +583,7 @@ public void testAddTwoFilesAsFileWithoutOCSP() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); container.addDataFile("src/test/resources/testFiles/helper-files/test.xml", "text/xml"); - this.createSignatureBy(container, SignatureProfile.B_BES, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.B_BES, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -592,7 +594,7 @@ public void testAddTwoFilesAsFileWithoutOCSP() throws Exception { public void testGetFileNameAndID() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); container.addDataFile("src/test/resources/testFiles/helper-files/test.xml", "text/xml"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -606,7 +608,7 @@ public void testGetFileNameAndID() throws Exception { public void testAddTwoFilesAsFileWithOCSP() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); container.addDataFile("src/test/resources/testFiles/helper-files/test.xml", "text/xml"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -617,7 +619,7 @@ public void testAddTwoFilesAsFileWithOCSP() throws Exception { public void saveToStream() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile(new ByteArrayInputStream(new byte[]{0x42}), "test_bytes.txt", "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); File expectedContainerAsFile = new File(this.getFileBy("bdoc")); OutputStream out = new FileOutputStream(expectedContainerAsFile); container.save(out); @@ -629,7 +631,7 @@ public void saveToStream() throws Exception { @Test public void saveExistingContainerToStream() throws Exception { Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/asics_testing_two_signatures.bdoc"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Assert.assertEquals(3, container.getSignatures().size()); InputStream inputStream = container.saveAsStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -643,7 +645,7 @@ public void saveExistingContainerToStream() throws Exception { @Test(expected = DigiDoc4JException.class) public void saveToStreamThrowsException() throws IOException { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); File expectedContainerAsFile = new File(this.getFileBy("bdoc")); OutputStream out = new FileOutputStream(expectedContainerAsFile); out.close(); @@ -670,7 +672,7 @@ public void saveExistingContainer() throws Exception { @Test public void containerIsLT() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); - this.createSignatureBy(container, SignatureProfile.LT, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.saveAsFile(file); container = ContainerOpener.open(file); @@ -680,14 +682,14 @@ public void containerIsLT() throws Exception { @Test(expected = DigiDoc4JException.class) public void signWithoutDataFile() throws Exception { - this.createSignatureBy(this.createEmptyContainerBy(Container.DocumentType.BDOC, Container.class), this.pkcs12SignatureToken); + this.createSignatureBy(this.createEmptyContainerBy(Container.DocumentType.BDOC, Container.class), pkcs12SignatureToken); } @Test public void nonStandardMimeType() { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/newtype"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); container = ContainerOpener.open(file); @@ -707,7 +709,7 @@ public void twoStepSigning() throws IOException { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); DataToSign dataToSign = SignatureBuilder.aSignature(container). - withSigningCertificate(this.pkcs12SignatureToken.getCertificate()).buildDataToSign(); + withSigningCertificate(pkcs12SignatureToken.getCertificate()).buildDataToSign(); Signature signature = dataToSign.finalize(this.sign(dataToSign.getDataToSign(), dataToSign.getDigestAlgorithm())); container.addSignature(signature); String file = this.getFileBy("bdoc"); @@ -722,7 +724,7 @@ public void twoStepSigning() throws IOException { Assert.assertTrue(StringUtils.isNotBlank(resultSignature.getId())); Assert.assertNotNull(resultSignature.getOCSPCertificate()); Assert.assertNotNull(resultSignature.getSigningCertificate()); - Assert.assertNotNull(resultSignature.getAdESSignature().length); + Assert.assertNotNull(resultSignature.getAdESSignature()); Assert.assertEquals(SignatureProfile.LT, resultSignature.getProfile()); Assert.assertNotNull(resultSignature.getTimeStampTokenCertificate()); List dataFiles = container.getDataFiles(); @@ -741,7 +743,7 @@ public void twoStepSigningVerifySignatureParameters() { Container container = ContainerBuilder.aContainer(Container.DocumentType.BDOC).build(); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); DataToSign dataToSign = SignatureBuilder.aSignature(container). - withSignatureDigestAlgorithm(DigestAlgorithm.SHA512).withSigningCertificate(this.pkcs12SignatureToken.getCertificate()). + withSignatureDigestAlgorithm(DigestAlgorithm.SHA512).withSigningCertificate(pkcs12SignatureToken.getCertificate()). withSignatureId("S99").withRoles("manager", "employee").withCity("city").withStateOrProvince("state"). withPostalCode("postalCode").withCountry("country").buildDataToSign(); byte[] signatureValue = this.sign(dataToSign.getDataToSign(), dataToSign.getDigestAlgorithm()); @@ -762,7 +764,7 @@ public void twoStepSigningVerifySignatureParameters() { public void testContainerCreationAsTSA() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); - this.createSignatureBy(container, SignatureProfile.LTA, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.LTA, pkcs12SignatureToken); Assert.assertNotNull(container.getSignatures().get(0).getOCSPCertificate()); } @@ -770,7 +772,7 @@ public void testContainerCreationAsTSA() throws Exception { public void testBDocTM() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); - this.createSignatureBy(container, SignatureProfile.LT_TM, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.LT_TM, pkcs12SignatureToken); Assert.assertTrue(container.validate().isValid()); } @@ -778,7 +780,7 @@ public void testBDocTM() throws Exception { public void testBDocTS() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); - this.createSignatureBy(container, SignatureProfile.LT, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); Assert.assertTrue(container.validate().isValid()); } @@ -786,7 +788,7 @@ public void testBDocTS() throws Exception { public void containerWithBESProfileHasNoValidationErrors() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); - this.createSignatureBy(container, SignatureProfile.B_BES, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.B_BES, pkcs12SignatureToken); Assert.assertEquals(SignatureProfile.B_BES, container.getSignatures().get(0).getProfile()); Assert.assertNull(container.getSignatures().get(0).getOCSPCertificate()); Assert.assertFalse(container.validate().isValid()); @@ -806,7 +808,7 @@ public void signWithECCCertificate() throws Exception { @Test public void zipFileComment() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt")); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.save(file); String expectedComment = Constant.USER_AGENT_STRING; @@ -826,7 +828,7 @@ public void signingMoreThanTwoFiles() throws Exception { container.addDataFile("src/test/resources/testFiles/special-char-files/dds_pakitud.zip", "text/plain"); container.addDataFile("src/test/resources/testFiles/special-char-files/dds_SK.jpg", "text/plain"); container.addDataFile("src/test/resources/testFiles/special-char-files/dds_acrobat.pdf", "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); Signature signature = container.getSignatures().get(0); TestAssert.assertSignatureMetadataContainsFileName(signature, "dds_dds_JÜRIÖÖ € žŠ päev.txt"); TestAssert.assertSignatureMetadataContainsFileName(signature, "dds_pakitud.zip"); @@ -837,9 +839,9 @@ public void signingMoreThanTwoFiles() throws Exception { @Test public void signatureFileNamesShouldBeInSequence() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt"), "text/plain"); - this.createSignatureBy(container, this.pkcs12SignatureToken); - this.createSignatureBy(container, this.pkcs12SignatureToken); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.saveAsFile(file); ZipFile zip = new ZipFile(file); @@ -854,7 +856,7 @@ public void whenSigningExistingContainer_withTwoSignatures_shouldCreateSignature Assert.assertNotNull(zip.getEntry("META-INF/signatures0.xml")); Assert.assertNotNull(zip.getEntry("META-INF/signatures1.xml")); Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/asics_testing_two_signatures.bdoc"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.saveAsFile(file); zip = new ZipFile(file); @@ -869,7 +871,7 @@ public void whenSigningExistingContainer_with_signatures1_xml_shouldCreateSignat Assert.assertNull(zip.getEntry("META-INF/signatures0.xml")); Assert.assertNotNull(zip.getEntry("META-INF/signatures1.xml")); Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/DigiDocService_spec_est.pdf-TM-j.bdoc"); - this.createSignatureBy(container, this.pkcs12SignatureToken); + this.createSignatureBy(container, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.saveAsFile(file); zip = new ZipFile(file); @@ -882,7 +884,7 @@ public void whenSigningExistingContainer_with_signatures1_xml_shouldCreateSignat public void addSignatureWithDuplicateSignatureId_throwsException() throws Exception { Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/test.asice"); Signature signature = SignatureBuilder.aSignature(container). - withSignatureToken(this.pkcs12SignatureToken).withSignatureId("S0").invokeSigning(); + withSignatureToken(pkcs12SignatureToken).withSignatureId("S0").invokeSigning(); container.addSignature(signature); } @@ -915,8 +917,8 @@ public void whenSigningContainer_withSignatureNameContainingNonNumericCharacters Assert.assertNull(zip.getEntry("META-INF/signatures0.xml")); Assert.assertNull(zip.getEntry("META-INF/signatures1.xml")); Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/valid-bdoc-ts-signature-file-name-with-non-numeric-characters.asice"); - this.createSignatureBy(container, SignatureProfile.LT, this.pkcs12SignatureToken); - this.createSignatureBy(container, SignatureProfile.LT, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); String file = this.getFileBy("bdoc"); container.saveAsFile(file); zip = new ZipFile(file); @@ -978,7 +980,7 @@ public void containerWithImplicitPolicy(){ public void bdocTM_OcspResponderCert_shouldContainResponderCertIdAttribute() throws Exception { Container container = this.createEmptyContainerBy(Container.DocumentType.BDOC); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); - BDocSignature signature = this.createSignatureBy(container, SignatureProfile.LT_TM, this.pkcs12SignatureToken); + BDocSignature signature = this.createSignatureBy(container, SignatureProfile.LT_TM, pkcs12SignatureToken); Assert.assertEquals(1, this.countOCSPResponderCertificates(signature.getOrigin().getDssSignature())); } @@ -1026,10 +1028,10 @@ public void settingUpOwnSignaturePolicy() throws Exception { signaturePolicy.setQualifier(qualifier); signaturePolicy.setDigestAlgorithm(digestAlgorithm); signaturePolicy.setSpuri(spuri); - Container container = ContainerBuilder.aContainer().build(); + Container container = ContainerBuilder.aContainer(Container.DocumentType.BDOC).build(); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); Signature signature = SignatureBuilder.aSignature(container).withOwnSignaturePolicy(signaturePolicy). - withSignatureDigestAlgorithm(DigestAlgorithm.SHA224).withSignatureToken(this.pkcs12SignatureToken). + withSignatureDigestAlgorithm(DigestAlgorithm.SHA224).withSignatureToken(pkcs12SignatureToken). withSignatureProfile(SignatureProfile.LT_TM).invokeSigning(); container.addSignature(signature); String file = this.getFileBy("bdoc"); @@ -1045,10 +1047,10 @@ public void settingUpOwnSignaturePolicy() throws Exception { @Test public void containerWithSignaturePolicyByDefault() throws Exception { - Container container = ContainerBuilder.aContainer().build(); + Container container = ContainerBuilder.aContainer(Container.DocumentType.BDOC).build(); container.addDataFile("src/test/resources/testFiles/helper-files/test.txt", "text/plain"); Signature signature = SignatureBuilder.aSignature(container).withSignatureDigestAlgorithm(DigestAlgorithm.SHA224). - withSignatureToken(this.pkcs12SignatureToken).withSignatureProfile(SignatureProfile.LT_TM).invokeSigning(); + withSignatureToken(pkcs12SignatureToken).withSignatureProfile(SignatureProfile.LT_TM).invokeSigning(); container.addSignature(signature); String file = this.getFileBy("bdoc"); container.saveAsFile(file); @@ -1058,7 +1060,7 @@ public void containerWithSignaturePolicyByDefault() throws Exception { Assert.assertEquals("https://www.sk.ee/repository/bdoc-spec21.pdf", policyId.getUrl()); Assert.assertEquals("" + XadesSignatureValidator.TM_POLICY, policyId.getIdentifier()); Assert.assertEquals(eu.europa.esig.dss.enumerations.DigestAlgorithm.SHA256, policyId.getDigest().getAlgorithm()); - Assert.assertArrayEquals(Base64.decodeBase64("7pudpH4eXlguSZY2e/pNbKzGsq+fu//woYL1SZFws1A="), policyId.getDigest().getValue()); + Assert.assertArrayEquals(Base64.decodeBase64("3Tl1oILSvOAWomdI9VeWV6IA/32eSXRUri9kPEz1IVs="), policyId.getDigest().getValue()); } @Test diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ContainerParticlesRemovalTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ContainerParticlesRemovalTest.java index 5a4e75e1f..d51f5dd32 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ContainerParticlesRemovalTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ContainerParticlesRemovalTest.java @@ -9,6 +9,7 @@ import org.digidoc4j.DataFile; import org.digidoc4j.Signature; import org.digidoc4j.SignatureProfile; +import org.digidoc4j.exceptions.SignatureNotFoundException; import org.digidoc4j.impl.asic.AsicEntry; import org.digidoc4j.impl.asic.AsicParseResult; import org.digidoc4j.impl.asic.asice.AsicEContainer; @@ -145,6 +146,88 @@ public void addAndRemoveSignatureToAlreadySignedContainerBeforeSaving_resultsWit assertSame(0, container.getContainerParseResult().getSignatures().size()); } + @Test + public void tryingToRemoveNonExistingSignatureFromBDocContainer_shouldThrowAnException() { + BDocContainer container = this.createEmptyContainerBy(BDOC); + container.addDataFile(mockDataFile()); + + Signature containerSignature = this.createSignatureBy(container, SignatureProfile.LT_TM, pkcs12SignatureToken); + Signature unrelatedSignature = this.createSignatureBy(BDOC, SignatureProfile.LT_TM, pkcs12SignatureToken); + + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(containerSignature)); + + SignatureNotFoundException caughtException = assertThrows( + SignatureNotFoundException.class, + () -> container.removeSignature(unrelatedSignature) + ); + + assertEquals("Signature not found: " + unrelatedSignature.getId(), caughtException.getMessage()); + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(containerSignature)); + } + + @Test + public void tryingToRemoveNonExistingSignatureFromASiCEContainer_shouldThrowAnException() { + AsicEContainer container = this.createEmptyContainerBy(ASICE); + container.addDataFile(mockDataFile()); + + Signature containerSignature = this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); + Signature unrelatedSignature = this.createSignatureBy(ASICE, SignatureProfile.LT, pkcs12SignatureToken); + + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(containerSignature)); + + SignatureNotFoundException caughtException = assertThrows( + SignatureNotFoundException.class, + () -> container.removeSignature(unrelatedSignature) + ); + + assertEquals("Signature not found: " + unrelatedSignature.getId(), caughtException.getMessage()); + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(containerSignature)); + } + + @Test + public void tryingToRemoveNonExistingSignatureByIndexFromBDocContainer_shouldThrowAnException() { + BDocContainer container = this.createEmptyContainerBy(BDOC); + container.addDataFile(mockDataFile()); + + Signature signature = this.createSignatureBy(container, SignatureProfile.LT_TM, pkcs12SignatureToken); + + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(signature)); + + SignatureNotFoundException caughtException = assertThrows( + SignatureNotFoundException.class, + () -> container.removeSignature(1) + ); + + assertEquals("Signature from index 1 not found", caughtException.getMessage()); + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(signature)); + } + + @Test + public void tryingToRemoveNonExistingSignatureByIndexFromASiCEContainer_shouldThrowAnException() { + AsicEContainer container = this.createEmptyContainerBy(ASICE); + container.addDataFile(mockDataFile()); + + Signature signature = this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); + + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(signature)); + + SignatureNotFoundException caughtException = assertThrows( + SignatureNotFoundException.class, + () -> container.removeSignature(1) + ); + + assertEquals("Signature from index 1 not found", caughtException.getMessage()); + assertEquals(1, container.getSignatures().size()); + assertTrue(container.getSignatures().contains(signature)); + } + @Test public void dataFileRemovalFromBDocContainerThroughoutContainerSavingAndOpening_shouldResultWithCompletelyRemovedData() { DataFile dataFile = mockDataFile(); diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/EmptyDataFilesBdocContainerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/EmptyDataFilesBdocContainerTest.java new file mode 100644 index 000000000..098f1b1c6 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/EmptyDataFilesBdocContainerTest.java @@ -0,0 +1,81 @@ +package org.digidoc4j.impl.bdoc; + +import org.digidoc4j.Configuration; +import org.digidoc4j.Constant; +import org.digidoc4j.Container; +import org.digidoc4j.ContainerOpener; +import org.digidoc4j.ContainerValidationResult; +import org.digidoc4j.SignatureBuilder; +import org.digidoc4j.exceptions.InvalidDataFileException; +import org.digidoc4j.impl.asic.EmptyDataFilesContainerTest; +import org.digidoc4j.test.TestAssert; +import org.junit.Assert; +import org.junit.Test; + +public class EmptyDataFilesBdocContainerTest extends EmptyDataFilesContainerTest { + + @Override + protected void before() { + configuration = Configuration.of(Configuration.Mode.TEST); + } + + @Override + protected Container.DocumentType getDocumentType() { + return Container.DocumentType.BDOC; + } + + @Test + public void testValidateSignedContainerWithEmptyDataFiles() { + Container container = loadSignedContainerWithEmptyDataFiles(); + + ContainerValidationResult validationResult = container.validate(); + + Assert.assertTrue(validationResult.isValid()); + Assert.assertNotNull(validationResult.getWarnings()); + Assert.assertEquals(2, validationResult.getWarnings().size()); + TestAssert.assertContainsError("Data file 'empty-file-2.txt' is empty", validationResult.getWarnings()); + TestAssert.assertContainsError("Data file 'empty-file-4.txt' is empty", validationResult.getWarnings()); + Assert.assertNotNull(validationResult.getContainerWarnings()); + Assert.assertEquals(2, validationResult.getContainerWarnings().size()); + TestAssert.assertContainsError("Data file 'empty-file-2.txt' is empty", validationResult.getContainerWarnings()); + TestAssert.assertContainsError("Data file 'empty-file-4.txt' is empty", validationResult.getContainerWarnings()); + } + + @Test + public void testInvokeSigningForSignedContainerWithEmptyDataFiles() { + Container container = loadSignedContainerWithEmptyDataFiles(); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> SignatureBuilder.aSignature(container) + .withSignatureToken(pkcs12SignatureToken) + .invokeSigning() + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file-2.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class, "Cannot sign empty datafile: empty-file-4.txt"); + } + + @Test + public void testBuildDataToSignForSignedContainerWithEmptyDataFiles() { + Container container = loadSignedContainerWithEmptyDataFiles(); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> SignatureBuilder.aSignature(container) + .withSignatureToken(pkcs12SignatureToken) + .buildDataToSign() + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file-2.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class, "Cannot sign empty datafile: empty-file-4.txt"); + } + + private Container loadSignedContainerWithEmptyDataFiles() { + Container container = ContainerOpener + .open("src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.bdoc", configuration); + Assert.assertEquals(Constant.BDOC_CONTAINER_TYPE, container.getType()); + return container; + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/EmptyDataFilesBdocSignatureFinalizerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/EmptyDataFilesBdocSignatureFinalizerTest.java new file mode 100644 index 000000000..eabbf0b19 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/EmptyDataFilesBdocSignatureFinalizerTest.java @@ -0,0 +1,18 @@ +package org.digidoc4j.impl.bdoc; + +import org.digidoc4j.DataFile; +import org.digidoc4j.SignatureParameters; +import org.digidoc4j.impl.EmptyDataFilesSignatureFinalizerTest; +import org.digidoc4j.impl.SignatureFinalizer; +import org.digidoc4j.impl.asic.asice.bdoc.BDocSignatureFinalizer; + +import java.util.List; + +public class EmptyDataFilesBdocSignatureFinalizerTest extends EmptyDataFilesSignatureFinalizerTest { + + @Override + protected SignatureFinalizer createSignatureFinalizerWithDataFiles(List dataFiles) { + return new BDocSignatureFinalizer(dataFiles, new SignatureParameters(), configuration); + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/IncompleteSigningTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/IncompleteSigningTest.java index ff6b0a465..323f6b9b2 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/IncompleteSigningTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/IncompleteSigningTest.java @@ -1,6 +1,9 @@ package org.digidoc4j.impl.bdoc; +import eu.europa.esig.dss.model.DSSException; import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.spi.client.http.DataLoader; +import org.apache.commons.codec.binary.Hex; import org.digidoc4j.AbstractTest; import org.digidoc4j.Configuration; import org.digidoc4j.Container; @@ -10,10 +13,9 @@ import org.digidoc4j.TSLCertificateSource; import org.digidoc4j.ValidationResult; import org.digidoc4j.exceptions.CertificateValidationException; -import org.digidoc4j.exceptions.NetworkException; import org.digidoc4j.exceptions.OCSPRequestFailedException; import org.digidoc4j.exceptions.TechnicalException; -import org.digidoc4j.exceptions.TslCertificateSourceInitializationException; +import org.digidoc4j.test.MockConfigurableDataLoader; import org.junit.Assert; import org.junit.Test; @@ -35,10 +37,10 @@ *

    * ...WhenTslCouldNotBeLoaded() - uses TEST configuration with empty SSL truststore in order to prevent TSL from loading. *

    - * ...WhenTslLoadingFails() - uses TEST configuration with invalid SSL truststore configuration in order to prevent TSL from loading. + * ...WhenTslLoadingFails() - uses TEST configuration with failing data loaders in order to prevent TSL from loading. *

    - * ...WhenDataLoadersFail() - uses TEST configuration with successfully loaded TSL and subsequently configured invalid SSL truststore - * configuration in order to make TSA and OCSP requests to fail. + * ...WhenDataLoadersFail() - uses TEST configuration with successfully loaded TSL and subsequently configured failing + * data loaders in order to make TSA and OCSP requests to fail. */ public class IncompleteSigningTest extends AbstractTest { @@ -209,19 +211,19 @@ public void signatureProfileBepesShouldNotFailWhenTslLoadingFails() { ); } - @Test(expected = NetworkException.class) + @Test(expected = TechnicalException.class) public void signatureProfileLtTmShouldFailWhenDataLoadersFail() { setUpTestConfigurationWithOkTslButFailingDataLoaders(); createSignatureBy(createNonEmptyContainerByConfiguration(), SignatureProfile.LT_TM, pkcs12SignatureToken); } - @Test(expected = NetworkException.class) + @Test(expected = TechnicalException.class) public void signatureProfileLtShouldFailWhenDataLoadersFail() { setUpTestConfigurationWithOkTslButFailingDataLoaders(); createSignatureBy(createNonEmptyContainerByConfiguration(), SignatureProfile.LT, pkcs12SignatureToken); } - @Test(expected = NetworkException.class) + @Test(expected = TechnicalException.class) public void signatureProfileLtaShouldFailWhenDataLoadersFail() { setUpTestConfigurationWithOkTslButFailingDataLoaders(); createSignatureBy(createNonEmptyContainerByConfiguration(), SignatureProfile.LTA, pkcs12SignatureToken); @@ -270,18 +272,14 @@ private void setUpTestConfigurationWithEmptyTSL() { private void setUpTestConfigurationWithFailingTSL() { configuration = Configuration.of(Configuration.Mode.TEST); - configuration.setSslTruststorePath("classpath:testFiles/truststores/empty-truststore.p12"); - configuration.setSslTruststorePassword("invalid-truststore-password"); - configuration.setSslTruststoreType("INVALID_TRUSTSTORE_TYPE"); + configureFailingDataLoaders(configuration); configuration.getTSL().invalidateCache(); } private void setUpTestConfigurationWithOkTslButFailingDataLoaders() { configuration = Configuration.of(Configuration.Mode.TEST); configuration.getTSL().refresh(); - configuration.setSslTruststorePath("classpath:testFiles/truststores/empty-truststore.p12"); - configuration.setSslTruststorePassword("invalid-truststore-password"); - configuration.setSslTruststoreType("INVALID_TRUSTSTORE_TYPE"); + configureFailingDataLoaders(configuration); } private void ensureCertificateTrustedByTSL(X509Certificate certificate) { @@ -315,4 +313,23 @@ private Signature reloadSignature(Signature signature, Configuration.Mode mode) } } + private static void configureFailingDataLoaders(Configuration configuration) { + DataLoader failingDataLoader = new MockConfigurableDataLoader() + .withGetter((url, refresh) -> { + String message = String.format("Failed to GET URL: %s", url); + if (refresh != null) { + message += String.format("; refresh: %s", refresh); + } + throw new DSSException(message); + }) + .withPoster((url, content) -> { + String contentHex = (content == null) ? "null" : Hex.encodeHexString(content); + throw new DSSException(String.format("Failed to POST URL: %s; content: %s", url, contentHex)); + }); + + configuration.setOcspDataLoaderFactory(() -> failingDataLoader); + configuration.setTslDataLoaderFactory(() -> failingDataLoader); + configuration.setTspDataLoaderFactory(() -> failingDataLoader); + } + } diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/UriEncodingTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/UriEncodingTest.java index 5e2c93bbb..c9409b47b 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/UriEncodingTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/UriEncodingTest.java @@ -12,6 +12,7 @@ import org.apache.xml.security.signature.Reference; import org.digidoc4j.*; +import org.digidoc4j.impl.asic.asice.AsicESignature; import org.digidoc4j.impl.asic.asice.bdoc.BDocSignature; import org.digidoc4j.test.util.TestDataBuilderUtil; import org.junit.Assert; @@ -61,7 +62,7 @@ public void validateContainer_withWhitespaceEncodedAsPlus_shouldBeValid() throws private void signAndAssert(String fileName, String expectedEncoding) { Signature signature = sign(fileName); Assert.assertTrue(signature.validateSignature().isValid()); - List referencesInSignature = ((BDocSignature) signature).getOrigin().getReferences(); + List referencesInSignature = ((AsicESignature) signature).getOrigin().getReferences(); Assert.assertEquals(expectedEncoding, referencesInSignature.get(0).getURI()); } diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ValidationTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ValidationTest.java index 683fd8aa5..f5f0be7b5 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ValidationTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/ValidationTest.java @@ -101,6 +101,20 @@ public void testValidate() throws Exception { Assert.assertEquals(0, container.validate().getErrors().size()); } + @Test + public void validCAServiceTypeIdentification() { + this.configuration = Configuration.of(Configuration.Mode.PROD); + TSLCertificateSource source = this.configuration.getTSL(); + Container container = ContainerBuilder.aContainer(). + fromExistingFile("src/test/resources/testFiles/valid-containers/valid-asice.asice"). + withConfiguration(this.configuration).build(); + this.addCertificateToTSL(Paths.get("src/test/resources/testFiles/certs/TEST_of_ESTEID-SK_2015.pem.crt"), source); + this.addCertificateToTSL(Paths.get("src/test/resources/testFiles/certs/SK-OCSP-RESPONDER-2011_test.cer"), source); + this.addCertificateToTSL(Paths.get("src/test/resources/testFiles/certs/DEMO_OF_SK_TSA_2014.cer"), source); + ContainerValidationResult result = container.validate(); + Assert.assertTrue(result.isValid()); + } + @Test public void testValidateBeforeAndAfterContainerChange() { Container container = this.createNonEmptyContainer(); @@ -109,14 +123,14 @@ public void testValidateBeforeAndAfterContainerChange() { Assert.assertTrue(result.isValid()); Assert.assertEquals(1, result.getReports().size()); - Assert.assertEquals("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", result.getReports().get(0).getSignedBy()); + Assert.assertEquals("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", result.getReports().get(0).getSignedBy()); this.createSignatureBy(container, this.pkcs12Esteid2018SignatureToken); result = container.validate(); Assert.assertTrue(result.isValid()); Assert.assertEquals(2, result.getReports().size()); - Assert.assertEquals("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", result.getReports().get(0).getSignedBy()); + Assert.assertEquals("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", result.getReports().get(0).getSignedBy()); Assert.assertEquals("JÕEORG,JAAK-KRISTJAN,38001085718", result.getReports().get(1).getSignedBy()); } @@ -162,8 +176,9 @@ public void signaturePolicyIsPolicyImplied(){ this.configuration); SignatureValidationResult validationResult = container.validate(); Assert.assertTrue(validationResult.isValid()); - Assert.assertEquals(1, validationResult.getWarnings().size()); + Assert.assertEquals(2, validationResult.getWarnings().size()); Assert.assertEquals("Signature created with implied policy, additional conditions may apply!", validationResult.getWarnings().get(0).getMessage()); + Assert.assertEquals("The authority info access is not present!", validationResult.getWarnings().get(1).getMessage()); } @Test @@ -270,6 +285,14 @@ public void revocationAndTimeStampDifferenceNotTooLarge() { .validate(); Assert.assertEquals(0, result.getErrors().size()); Assert.assertEquals(2, result.getWarnings().size()); + TestAssert.assertContainsError( + "The difference between the OCSP response time and the signature timestamp is in allowable range", + result.getWarnings() + ); + TestAssert.assertContainsError( + "The authority info access is not present!", + result.getWarnings() + ); } @Test @@ -359,9 +382,9 @@ public void invalidNoncePolicyOid() { .open("src/test/resources/prodFiles/invalid-containers/23608_bdoc21-invalid-nonce-policy-oid.bdoc", PROD_CONFIGURATION); SignatureValidationResult result = container.validate(); List errors = result.getErrors(); - Assert.assertEquals(1, errors.size()); - Assert.assertEquals("(Signature ID: S0) - Wrong policy identifier: 1.3.6.1.4.1.10015.1000.3.4.3", - errors.get(0).toString()); + Assert.assertEquals(2, errors.size()); + TestAssert.assertContainsError("Wrong policy identifier: 1.3.6.1.4.1.10015.1000.3.4.3", errors); + TestAssert.assertContainsError("The certificate is not related to a granted status!", errors); } @Test @@ -425,10 +448,11 @@ public void nonceIncorrectContent() { .open("src/test/resources/prodFiles/invalid-containers/nonce-vale-sisu.bdoc", PROD_CONFIGURATION_WITH_TEST_POLICY); SignatureValidationResult result = container.validate(); List errors = result.getErrors(); - Assert.assertEquals(5, errors.size()); - Assert.assertEquals("(Signature ID: S0) - Wrong policy identifier: 1.3.6.1.4.1.10015.1000.2.10.10", - errors.get(0).toString()); - Assert.assertEquals("(Signature ID: S0) - OCSP nonce is invalid", errors.get(3).toString()); + Assert.assertEquals(6, errors.size()); + TestAssert.assertContainsError("OCSP nonce is invalid", errors); + TestAssert.assertContainsError("Wrong policy identifier: 1.3.6.1.4.1.10015.1000.2.10.10", errors); + TestAssert.assertContainsError("The result of the LTV validation process is not acceptable to continue the process!", errors); + TestAssert.assertContainsError("The certificate is not related to a granted status!", errors); } @Test @@ -567,6 +591,54 @@ public void bdocTM_signedWithValidCert_isExpiredByNow_shouldBeValid() throws Exc Assert.assertTrue(test.isValid()); } + @Test + public void bdocTM_noOcspCertificateInSignature_OcspCertificateInOcspToken_shouldBeValid() { + Configuration configuration = new Configuration(Configuration.Mode.TEST); + Container container = ContainerBuilder.aContainer(). + fromExistingFile("src/test/resources/testFiles/valid-containers/NoAdditionalOcspCertificate.bdoc"). + withConfiguration(configuration) + .build(); + ContainerValidationResult test = container.validate(); + Assert.assertTrue(test.isValid()); + } + + @Test + public void bdocTM_noOcspCertificateInSignatureNorInOcspToken_shouldBeInvalid() { + Configuration configuration = new Configuration(Configuration.Mode.TEST); + Container container = ContainerBuilder.aContainer(). + fromExistingFile("src/test/resources/testFiles/invalid-containers/NoOcspCertificateAnywhere.bdoc"). + withConfiguration(configuration) + .build(); + ContainerValidationResult test = container.validate(); + Assert.assertFalse(test.isValid()); + Assert.assertEquals(0, test.getContainerErrors().size()); + Assert.assertEquals(1, test.getErrors().size()); + TestAssert.assertContainsError("OCSP Responder does not meet TM requirements", test.getErrors()); + } + + @Test + public void asiceLT_noAdditionalCertificatesInSignature_shouldBeValid() { + Configuration configuration = new Configuration(Configuration.Mode.TEST); + Container container = ContainerBuilder.aContainer(). + fromExistingFile("src/test/resources/testFiles/valid-containers/NoAdditionalCertificates_LT.asice"). + withConfiguration(configuration) + .build(); + ContainerValidationResult test = container.validate(); + Assert.assertTrue(test.isValid()); + } + + @Test + public void asiceLT_noOcspCertificateInSignatureNorInOcspTokenButInTsl_shouldBeValid() { + Configuration configuration = new Configuration(Configuration.Mode.TEST); + addCertificateToTSL(Paths.get("src/test/resources/testFiles/certs/SK_TSA.pem.crt"), configuration.getTSL()); + Container container = ContainerBuilder.aContainer(). + fromExistingFile("src/test/resources/testFiles/valid-containers/NoOcspCertificateAnywhere_LT_liveTS.asice"). + withConfiguration(configuration) + .build(); + ContainerValidationResult test = container.validate(); + Assert.assertTrue(test.isValid()); + } + @Test public void signaturesWithCrlShouldBeInvalid() throws Exception { SignatureValidationResult result = this.openContainerByConfiguration( @@ -712,18 +784,18 @@ public void validateSpuriElement_UriIsvalid() throws Exception { } @Test - public void validateBDocTs_Isvalid() throws Exception { + public void validateBDocTs_Invalid() throws Exception { Container container = ContainerOpener.open("src/test/resources/prodFiles/invalid-containers/bdoc21-ts-ok.bdoc", PROD_CONFIGURATION); SignatureValidationResult result = container.validate(); Assert.assertFalse(result.isValid()); - Assert.assertEquals(8, result.getErrors().size()); + Assert.assertEquals(9, result.getErrors().size()); + TestAssert.assertContainsError("The result of the timestamps validation process is not conclusive!", result.getErrors()); + TestAssert.assertContainsError("The certificate chain for timestamp is not trusted, it does not contain a trust anchor.", result.getErrors()); + TestAssert.assertContainsError("Signature has an invalid timestamp", result.getErrors()); + TestAssert.assertContainsError("The result of the LTV validation process is not acceptable to continue the process!", result.getErrors()); + TestAssert.assertContainsError("The certificate is not related to a granted status!", result.getErrors()); TestAssert.assertContainsError( - "(Signature ID: S0) - The result of the timestamps validation process is not conclusive!", - result.getErrors()); - TestAssert.assertContainsError( - "(Signature ID: S0) - Signature has an invalid timestamp", result.getErrors()); - TestAssert.assertContainsError( - "(Signature ID: S0) - Manifest file has an entry for file with mimetype but the " + + "Manifest file has an entry for file with mimetype but the " + "signature file for signature S0 indicates the mimetype is <>", result.getErrors()); } @@ -821,6 +893,20 @@ public void container_withPssSignature_shouldBeValid(){ TestAssert.assertContainerIsValid(container); } + @Test + public void container_withExpiredAIAOCSP_LT_shouldBeInvalid() { + Container container = ContainerOpener.open("src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLT.asice"); + ContainerValidationResult validationResult = container.validate(); + Assert.assertEquals(2, validationResult.getErrors().size()); + } + + @Test + public void container_withExpiredAIAOCSP_LTA_shouldBeInvalid() { + Container container = ContainerOpener.open("src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLTA.asice"); + ContainerValidationResult validationResult = container.validate(); + Assert.assertEquals(2, validationResult.getErrors().size()); + } + /* * RESTRICTED METHODS */ diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicEContainerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicEContainerTest.java new file mode 100644 index 000000000..47dd3080e --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicEContainerTest.java @@ -0,0 +1,135 @@ +package org.digidoc4j.impl.bdoc.asic; + +import org.digidoc4j.Configuration; +import org.digidoc4j.Constant; +import org.digidoc4j.Container; +import org.digidoc4j.ContainerOpener; +import org.digidoc4j.ContainerValidationResult; +import org.digidoc4j.SignatureBuilder; +import org.digidoc4j.exceptions.InvalidDataFileException; +import org.digidoc4j.impl.asic.EmptyDataFilesContainerTest; +import org.digidoc4j.test.TestAssert; +import org.junit.Assert; +import org.junit.Test; + +public class EmptyDataFilesAsicEContainerTest extends EmptyDataFilesContainerTest { + + @Override + protected void before() { + configuration = Configuration.of(Configuration.Mode.TEST); + } + + @Override + protected Container.DocumentType getDocumentType() { + return Container.DocumentType.ASICE; + } + + @Test + public void testValidateUnsignedContainerWithEmptyDataFiles() { + Container container = loadUnsignedContainerWithEmptyDataFiles(); + + ContainerValidationResult validationResult = container.validate(); + + Assert.assertTrue(validationResult.isValid()); + Assert.assertNotNull(validationResult.getWarnings()); + Assert.assertEquals(2, validationResult.getWarnings().size()); + TestAssert.assertContainsError("Data file 'empty-file-2.txt' is empty", validationResult.getWarnings()); + TestAssert.assertContainsError("Data file 'empty-file-4.txt' is empty", validationResult.getWarnings()); + Assert.assertNotNull(validationResult.getContainerWarnings()); + Assert.assertEquals(2, validationResult.getContainerWarnings().size()); + TestAssert.assertContainsError("Data file 'empty-file-2.txt' is empty", validationResult.getContainerWarnings()); + TestAssert.assertContainsError("Data file 'empty-file-4.txt' is empty", validationResult.getContainerWarnings()); + } + + @Test + public void testValidateSignedContainerWithEmptyDataFiles() { + Container container = loadSignedContainerWithEmptyDataFiles(); + + ContainerValidationResult validationResult = container.validate(); + + Assert.assertTrue(validationResult.isValid()); + Assert.assertNotNull(validationResult.getWarnings()); + Assert.assertEquals(2, validationResult.getWarnings().size()); + TestAssert.assertContainsError("Data file 'empty-file-2.txt' is empty", validationResult.getWarnings()); + TestAssert.assertContainsError("Data file 'empty-file-4.txt' is empty", validationResult.getWarnings()); + Assert.assertNotNull(validationResult.getContainerWarnings()); + Assert.assertEquals(2, validationResult.getContainerWarnings().size()); + TestAssert.assertContainsError("Data file 'empty-file-2.txt' is empty", validationResult.getContainerWarnings()); + TestAssert.assertContainsError("Data file 'empty-file-4.txt' is empty", validationResult.getContainerWarnings()); + } + + @Test + public void testInvokeSigningForUnsignedContainerWithEmptyDataFiles() { + Container container = loadUnsignedContainerWithEmptyDataFiles(); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> SignatureBuilder.aSignature(container) + .withSignatureToken(pkcs12Esteid2018SignatureToken) + .invokeSigning() + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file-2.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class, "Cannot sign empty datafile: empty-file-4.txt"); + } + + @Test + public void testBuildDataToSignForUnsignedContainerWithEmptyDataFiles() { + Container container = loadUnsignedContainerWithEmptyDataFiles(); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> SignatureBuilder.aSignature(container) + .withSignatureToken(pkcs12Esteid2018SignatureToken) + .buildDataToSign() + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file-2.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class, "Cannot sign empty datafile: empty-file-4.txt"); + } + + @Test + public void testInvokeSigningForSignedContainerWithEmptyDataFiles() { + Container container = loadSignedContainerWithEmptyDataFiles(); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> SignatureBuilder.aSignature(container) + .withSignatureToken(pkcs12SignatureToken) + .invokeSigning() + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file-2.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class, "Cannot sign empty datafile: empty-file-4.txt"); + } + + @Test + public void testBuildDataToSignForSignedContainerWithEmptyDataFiles() { + Container container = loadSignedContainerWithEmptyDataFiles(); + + InvalidDataFileException caughtException = assertThrows( + InvalidDataFileException.class, + () -> SignatureBuilder.aSignature(container) + .withSignatureToken(pkcs12SignatureToken) + .buildDataToSign() + ); + + Assert.assertEquals("Cannot sign empty datafile: empty-file-2.txt", caughtException.getMessage()); + TestAssert.assertSuppressed(caughtException, InvalidDataFileException.class, "Cannot sign empty datafile: empty-file-4.txt"); + } + + private Container loadUnsignedContainerWithEmptyDataFiles() { + Container container = ContainerOpener + .open("src/test/resources/testFiles/valid-containers/unsigned-container-with-empty-datafiles.asice", configuration); + Assert.assertEquals(Constant.ASICE_CONTAINER_TYPE, container.getType()); + return container; + } + + private Container loadSignedContainerWithEmptyDataFiles() { + Container container = ContainerOpener + .open("src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.asice", configuration); + Assert.assertEquals(Constant.ASICE_CONTAINER_TYPE, container.getType()); + return container; + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicESignatureFinalizerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicESignatureFinalizerTest.java new file mode 100644 index 000000000..4848799c8 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicESignatureFinalizerTest.java @@ -0,0 +1,18 @@ +package org.digidoc4j.impl.bdoc.asic; + +import org.digidoc4j.DataFile; +import org.digidoc4j.SignatureParameters; +import org.digidoc4j.impl.EmptyDataFilesSignatureFinalizerTest; +import org.digidoc4j.impl.SignatureFinalizer; +import org.digidoc4j.impl.asic.asice.AsicESignatureFinalizer; + +import java.util.List; + +public class EmptyDataFilesAsicESignatureFinalizerTest extends EmptyDataFilesSignatureFinalizerTest { + + @Override + protected SignatureFinalizer createSignatureFinalizerWithDataFiles(List dataFiles) { + return new AsicESignatureFinalizer(dataFiles, new SignatureParameters(), configuration); + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicSContainerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicSContainerTest.java new file mode 100644 index 000000000..ead85151a --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicSContainerTest.java @@ -0,0 +1,13 @@ +package org.digidoc4j.impl.bdoc.asic; + +import org.digidoc4j.Container; +import org.digidoc4j.impl.asic.EmptyDataFilesContainerTest; + +public class EmptyDataFilesAsicSContainerTest extends EmptyDataFilesContainerTest { + + @Override + protected Container.DocumentType getDocumentType() { + return Container.DocumentType.ASICS; + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicSignatureFinalizerTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicSignatureFinalizerTest.java new file mode 100644 index 000000000..57366661c --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/EmptyDataFilesAsicSignatureFinalizerTest.java @@ -0,0 +1,18 @@ +package org.digidoc4j.impl.bdoc.asic; + +import org.digidoc4j.DataFile; +import org.digidoc4j.SignatureParameters; +import org.digidoc4j.impl.EmptyDataFilesSignatureFinalizerTest; +import org.digidoc4j.impl.SignatureFinalizer; +import org.digidoc4j.impl.asic.AsicSignatureFinalizer; + +import java.util.List; + +public class EmptyDataFilesAsicSignatureFinalizerTest extends EmptyDataFilesSignatureFinalizerTest { + + @Override + protected SignatureFinalizer createSignatureFinalizerWithDataFiles(List dataFiles) { + return new AsicSignatureFinalizer(dataFiles, new SignatureParameters(), configuration); + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/TimeStampTokenTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/TimeStampTokenTest.java index d07982490..d4bea3a2b 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/TimeStampTokenTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/asic/TimeStampTokenTest.java @@ -15,6 +15,7 @@ import org.digidoc4j.impl.asic.manifest.ManifestValidator; import org.digidoc4j.test.TestAssert; import org.digidoc4j.test.util.TestDigiDoc4JUtil; +import org.digidoc4j.test.util.TestSigningUtil; import org.hamcrest.core.StringContains; import org.junit.Assert; import org.junit.Rule; @@ -165,7 +166,7 @@ public void tstASICSAddPKCS12Signature() throws Exception { "text/plain", "-datst", "SHA256", "-tst"}; TestDigiDoc4JUtil.call(parameters); parameters = new String[]{"-in", fileName, "-type", "ASICS", "-add", "src/test/resources/testFiles/helper-files/dds_колючей стерне.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test"}; + "text/plain", "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Assert.assertThat(this.stdOut.getLog(), StringContains.containsString( "This container has already timestamp. Should be no signatures in case of timestamped ASiCS container.")); @@ -175,7 +176,7 @@ public void tstASICSAddPKCS12Signature() throws Exception { public void asicsAddPKCS12Signature() throws Exception { String fileName = this.getFileBy("asics"); String[] parameters = new String[]{"-in", fileName, "-type", "ASICS", "-add", "src/test/resources/testFiles/helper-files/dds_колючей стерне.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test"}; + "text/plain", "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Assert.assertThat(this.stdOut.getLog(), StringContains.containsString("Not supported: Not for ASiC-S container")); diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/report/ValidationReportTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/report/ValidationReportTest.java index 07540ccc0..dfc52c105 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/report/ValidationReportTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/bdoc/report/ValidationReportTest.java @@ -30,7 +30,7 @@ public class ValidationReportTest extends AbstractTest { @Test public void validContainerWithOneSignature() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt")); - Signature signature = this.createSignatureBy(container, SignatureProfile.LT, this.pkcs12SignatureToken); + Signature signature = this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); String signatureId = signature.getId(); SignatureValidationResult result = container.validate(); Assert.assertTrue(result.isValid()); @@ -41,13 +41,13 @@ public void validContainerWithOneSignature() throws Exception { TestAssert.assertXPathHasValue("1", "count(/SimpleReport/Signature)", report); TestAssert.assertXPathHasValue(signatureId, "/SimpleReport/Signature/@Id", report); TestAssert.assertXPathHasValue("XAdES-BASELINE-LT", "/SimpleReport/Signature/@SignatureFormat", report); - TestAssert.assertXPathHasValue("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", "/SimpleReport/Signature[@Id='" + signatureId + "']/SignedBy", report); + TestAssert.assertXPathHasValue("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", "/SimpleReport/Signature[@Id='" + signatureId + "']/SignedBy", report); TestAssert.assertXPathHasValue("TOTAL_PASSED", "/SimpleReport/Signature[@Id='" + signatureId + "']/Indication", report); TestAssert.assertXPathHasValue("Full document", "/SimpleReport/Signature[@Id='" + signatureId + "']/SignatureScope", report); TestAssert.assertXPathHasValue("test.txt", "/SimpleReport/Signature[@Id='" + signatureId + "']/SignatureScope/@name", report); TestAssert.assertXPathHasValue("", "/SimpleReport/Signature[@Id='" + signatureId + "']/Errors", report); TestAssert.assertXPathHasValue("true", "count(/SimpleReport/Signature[@Id='" + signatureId + "']/CertificateChain/Certificate) > 1", report); - TestAssert.assertXPathHasValue("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", "/SimpleReport/Signature[@Id='" + signatureId + + TestAssert.assertXPathHasValue("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", "/SimpleReport/Signature[@Id='" + signatureId + "']/CertificateChain/Certificate[1]/qualifiedName", report); } @@ -55,7 +55,7 @@ public void validContainerWithOneSignature() throws Exception { public void validContainerWithOneTmSignature() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt")); container.addDataFile("src/test/resources/testFiles/special-char-files/dds_acrobat.pdf", MimeType.PDF.getMimeTypeString()); - this.createSignatureBy(container, SignatureProfile.LT_TM, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.LT_TM, pkcs12SignatureToken); String report = container.validate().getReport(); TestAssert.assertXPathHasValue("1", "/SimpleReport/SignaturesCount", report); TestAssert.assertXPathHasValue("1", "/SimpleReport/ValidSignaturesCount", report); @@ -65,13 +65,13 @@ public void validContainerWithOneTmSignature() throws Exception { TestAssert.assertXPathHasValue("test.txt", "/SimpleReport/Signature/SignatureScope[1]/@name", report); TestAssert.assertXPathHasValue("dds_acrobat.pdf", "/SimpleReport/Signature/SignatureScope[2]/@name", report); TestAssert.assertXPathHasValue("true", "count(/SimpleReport/Signature/CertificateChain/Certificate) > 1", report); - TestAssert.assertXPathHasValue("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", "/SimpleReport/Signature/CertificateChain/Certificate[1]/qualifiedName", report); + TestAssert.assertXPathHasValue("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", "/SimpleReport/Signature/CertificateChain/Certificate[1]/qualifiedName", report); } @Test public void containerWithOneBesSignature() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt")); - this.createSignatureBy(container, SignatureProfile.B_BES, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.B_BES, pkcs12SignatureToken); String report = container.validate().getReport(); TestAssert.assertXPathHasValue("1", "/SimpleReport/SignaturesCount", report); TestAssert.assertXPathHasValue("0", "/SimpleReport/ValidSignaturesCount", report); @@ -81,13 +81,13 @@ public void containerWithOneBesSignature() throws Exception { TestAssert.assertXPathHasValue("TRY_LATER", "/SimpleReport/Signature/SubIndication", report); TestAssert.assertXPathHasValue("test.txt", "/SimpleReport/Signature/SignatureScope/@name", report); TestAssert.assertXPathHasValue("true", "count(/SimpleReport/Signature/CertificateChain/Certificate) > 1", report); - TestAssert.assertXPathHasValue("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", "/SimpleReport/Signature/CertificateChain/Certificate[1]/qualifiedName", report); + TestAssert.assertXPathHasValue("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", "/SimpleReport/Signature/CertificateChain/Certificate[1]/qualifiedName", report); } @Test public void containerWithOneEpesSignature() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt")); - this.createSignatureBy(container, SignatureProfile.B_EPES, this.pkcs12SignatureToken); + this.createSignatureBy(container, SignatureProfile.B_EPES, pkcs12SignatureToken); String report = container.validate().getReport(); TestAssert.assertXPathHasValue("1", "/SimpleReport/SignaturesCount", report); TestAssert.assertXPathHasValue("0", "/SimpleReport/ValidSignaturesCount", report); @@ -97,14 +97,14 @@ public void containerWithOneEpesSignature() throws Exception { TestAssert.assertXPathHasValue("TRY_LATER", "/SimpleReport/Signature/SubIndication", report); TestAssert.assertXPathHasValue("test.txt", "/SimpleReport/Signature/SignatureScope/@name", report); TestAssert.assertXPathHasValue("true", "count(/SimpleReport/Signature/CertificateChain/Certificate) > 1", report); - TestAssert.assertXPathHasValue("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", "/SimpleReport/Signature/CertificateChain/Certificate[1]/qualifiedName", report); + TestAssert.assertXPathHasValue("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", "/SimpleReport/Signature/CertificateChain/Certificate[1]/qualifiedName", report); } @Test public void validContainerWithTwoSignatures() throws Exception { Container container = this.createNonEmptyContainerBy(Paths.get("src/test/resources/testFiles/helper-files/test.txt")); - Signature signature1 = this.createSignatureBy(container, SignatureProfile.LT_TM, this.pkcs12SignatureToken); - Signature signature2 = this.createSignatureBy(container, SignatureProfile.LT, this.pkcs12SignatureToken); + Signature signature1 = this.createSignatureBy(container, SignatureProfile.LT_TM, pkcs12SignatureToken); + Signature signature2 = this.createSignatureBy(container, SignatureProfile.LT, pkcs12SignatureToken); SignatureValidationResult result = container.validate(); Assert.assertTrue(result.isValid()); String report = result.getReport(); @@ -118,9 +118,9 @@ public void validContainerWithTwoSignatures() throws Exception { TestAssert.assertXPathHasValue("test.txt", "/SimpleReport/Signature[1]/SignatureScope/@name", report); TestAssert.assertXPathHasValue("test.txt", "/SimpleReport/Signature[2]/SignatureScope/@name", report); TestAssert.assertXPathHasValue("true", "count(/SimpleReport/Signature[1]/CertificateChain/Certificate) > 1", report); - TestAssert.assertXPathHasValue("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", "/SimpleReport/Signature[1]/CertificateChain/Certificate[1]/qualifiedName", report); + TestAssert.assertXPathHasValue("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", "/SimpleReport/Signature[1]/CertificateChain/Certificate[1]/qualifiedName", report); TestAssert.assertXPathHasValue("true", "count(/SimpleReport/Signature[2]/CertificateChain/Certificate) > 1", report); - TestAssert.assertXPathHasValue("ŽÕRINÜWŠKY,MÄRÜ-LÖÖZ,11404176865", "/SimpleReport/Signature[2]/CertificateChain/Certificate[1]/qualifiedName", report); + TestAssert.assertXPathHasValue("O’CONNEŽ-ŠUSLIK TESTNUMBER,MARY ÄNN,60001013739", "/SimpleReport/Signature[2]/CertificateChain/Certificate[1]/qualifiedName", report); } @Test diff --git a/digidoc4j/src/test/java/org/digidoc4j/impl/ddoc/ValidationTest.java b/digidoc4j/src/test/java/org/digidoc4j/impl/ddoc/ValidationTest.java index d615381b7..dcde7d5d5 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/impl/ddoc/ValidationTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/impl/ddoc/ValidationTest.java @@ -17,6 +17,15 @@ public void setInvalidOcspResponder() { TestAssert.assertContainsError("OCSP Responder does not meet TM requirements", result.getErrors()); } + @Test + public void missingURIAttributeValue() { + ConfigManagerInitializer.forceInitConfigManager(this.configuration); + Container container = ContainerBuilder.aContainer() + .fromExistingFile("src/test/resources/testFiles/invalid-containers/23133_ddoc-12.ddoc").build(); + SignatureValidationResult result = container.validate(); + TestAssert.assertContainsError("URI Attribute value is required", result.getErrors()); + } + @Test public void defaultOcspResponderSuccessful(){ ConfigManagerInitializer.forceInitConfigManager(this.configuration); diff --git a/digidoc4j/src/test/java/org/digidoc4j/jvm/JvmParametersTest.java b/digidoc4j/src/test/java/org/digidoc4j/jvm/JvmParametersTest.java index 4942f35bd..82b2d8f7a 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/jvm/JvmParametersTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/jvm/JvmParametersTest.java @@ -54,8 +54,7 @@ public void dataLoaderHttpsProxyEmptyTest() { ProxyProperties httpsProperties = dataLoader.getProxyConfig().getHttpsProperties(); Assert.assertEquals("http.proxyHost", httpProperties.getHost()); Assert.assertEquals(8800, httpProperties.getPort()); - Assert.assertEquals(null, httpsProperties.getHost()); - Assert.assertEquals(0, httpsProperties.getPort()); + Assert.assertNull(httpsProperties); } @Test @@ -67,8 +66,7 @@ public void dataLoaderHttpProxyEmptyTest() { DataLoaderDecorator.decorateWithProxySettings(dataLoader, this.configuration); ProxyProperties httpProperties = dataLoader.getProxyConfig().getHttpProperties(); ProxyProperties httpsProperties = dataLoader.getProxyConfig().getHttpsProperties(); - Assert.assertEquals(null, httpProperties.getHost()); - Assert.assertEquals(0, httpProperties.getPort()); + Assert.assertNull(httpProperties); Assert.assertEquals("https.proxyHost", httpsProperties.getHost()); Assert.assertEquals(10000, httpsProperties.getPort()); } diff --git a/digidoc4j/src/test/java/org/digidoc4j/main/DigiDoc4JTest.java b/digidoc4j/src/test/java/org/digidoc4j/main/DigiDoc4JTest.java index 01f30a96c..2a1634443 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/main/DigiDoc4JTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/main/DigiDoc4JTest.java @@ -24,6 +24,7 @@ import org.digidoc4j.test.TestAssert; import org.digidoc4j.test.util.TestCommonUtil; import org.digidoc4j.test.util.TestDigiDoc4JUtil; +import org.digidoc4j.test.util.TestSigningUtil; import org.hamcrest.core.StringContains; import org.junit.Assert; import org.junit.Ignore; @@ -55,14 +56,14 @@ public void testComposingAndSigningAndAddingDataToSignFile() { String dataToSignFile = this.getFileBy("ser"); String[] parameters = new String[]{"-in", containerFile, "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-dts", dataToSignFile, "text/plain", "-cert", "src/test/resources/testFiles/certs/signout.pem"}; + "text/plain", "-dts", dataToSignFile, "text/plain", "-cert", "src/test/resources/testFiles/certs/sign_RSA_from_TEST_of_ESTEIDSK2015.pem"}; TestDigiDoc4JUtil.call(parameters); Assert.assertTrue(String.format("No data to sign file <%s>", dataToSignFile), new File(dataToSignFile).exists ()); Assert.assertTrue(String.format("No container file <%s>", containerFile), new File(containerFile).exists()); String signatureFile = this.getFileBy("sig"); parameters = new String[]{"-dts", dataToSignFile, - "-sig", signatureFile, "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-sig", signatureFile, "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Assert.assertTrue(String.format("No signature file <%s>", signatureFile), new File(signatureFile).exists()); parameters = new String[]{"-in", containerFile, "-sig", signatureFile, @@ -75,8 +76,9 @@ public void testComposingAndSigningAndAddingDataToSignFile() { public void createsContainerWithSignatureProfileIsTSAForBDoc() throws Exception { String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, "-type", "BDOC", - "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test", "-profile", "LTA"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-profile", "LTA"}; TestDigiDoc4JUtil.call(parameters); Container container = ContainerOpener.open(file); Assert.assertEquals(SignatureProfile.LTA, container.getSignatures().get(0).getProfile()); @@ -86,8 +88,9 @@ public void createsContainerWithSignatureProfileIsTSAForBDoc() throws Exception public void createsContainerWithSignatureProfileIsTSForBDoc() throws Exception { String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, "-type", "BDOC", - "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test", "-profile", "LT"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-profile", "LT"}; TestDigiDoc4JUtil.call(parameters); Assert.assertEquals(SignatureProfile.LT, ContainerOpener.open(file).getSignatures().get(0).getProfile()); } @@ -95,8 +98,10 @@ public void createsContainerWithSignatureProfileIsTSForBDoc() throws Exception { @Test public void createsContainerWithSignatureProfileIsTSForAsice() throws Exception { String fileName = this.getFileBy("asice"); - String[] params = new String[]{"-in", fileName, "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test", "-profile", "LT"}; + String[] params = new String[]{"-in", fileName, + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-profile", "LT"}; System.setProperty("digidoc4j.mode", "TEST"); TestDigiDoc4JUtil.call(params); Container container = ContainerOpener.open(fileName); @@ -109,8 +114,9 @@ public void createsContainerWithSignatureProfileIsTSForAsice() throws Exception public void createsContainerWithSignatureProfileIsBESForBDoc() throws Exception { String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, "-type", "BDOC", - "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test", "-profile", "B_BES"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-profile", "B_BES"}; TestDigiDoc4JUtil.call(parameters); Assert.assertEquals(SignatureProfile.B_BES, ContainerOpener.open(file).getSignatures().get(0).getProfile()); } @@ -139,8 +145,9 @@ public void createsECCSignature() throws Exception { public void createsContainerWithUnknownSignatureProfile() throws Exception { String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, "-type", "BDOC", - "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test", "-profile", "Unknown"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-profile", "Unknown"}; TestDigiDoc4JUtil.call(parameters); Assert.assertEquals(SignatureProfile.LT, ContainerOpener.open(file).getSignatures().get(0).getProfile()); } @@ -159,8 +166,9 @@ public void checkAssertion() throws Exception { }); String file = this.getFileBy("ddoc"); String[] parameters = new String[]{"-in", file, "-type", "DDOC", - "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test", "-profile", "LT_TM"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-profile", "LT_TM"}; DigiDoc4J.main(parameters); } @@ -180,8 +188,9 @@ public void checkAssertion() throws Exception { Container container = ContainerOpener.open("src/test/resources/testFiles/valid-containers/ddoc_for_testing.ddoc"); container.saveAsFile(file); String[] parameters = new String[]{"-in", file, "-type", "DDOC", - "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test", "-profile", "LT_TM"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-profile", "LT_TM"}; DigiDoc4J.main(parameters); } @@ -189,8 +198,8 @@ public void checkAssertion() throws Exception { public void createsContainerWithTypeSettingBDoc() throws Exception { String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, "-type", "BDOC", - "-add", "src/test/resources/testFiles/helper-files/test.txt", - "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Container container = ContainerOpener.open(file); assertAsicEContainer(container); @@ -216,8 +225,8 @@ public void commandLineDigidoc4jModeOverwritesDefault() throws Exception { public void createsContainerWithTypeSettingBasedOnFileExtensionBDoc() throws Exception { String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, - "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Container container = ContainerOpener.open(file); assertAsicEContainer(container); @@ -227,8 +236,8 @@ public void createsContainerWithTypeSettingBasedOnFileExtensionBDoc() throws Exc public void createsContainerWithTypeSettingBDocIfNoSuitableFileExtensionAndNoType() throws Exception { String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, - "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Container container = ContainerOpener.open(file); assertAsicEContainer(container); @@ -239,8 +248,8 @@ public void createsContainerAndSignsIt() throws Exception { this.systemExit.expectSystemExitWithStatus(0); String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, - "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; DigiDoc4J.main(parameters); } @@ -266,7 +275,7 @@ public void itShouldNotBePossible_ToSignWithBoth_Pkcs11AndPkcs12() throws Except String[] parameters = new String[]{"-in", file, "-add", "src/test/resources/testFiles/helper-files/test.txt", "text/plain", "-pkcs11", "/usr/local/lib/opensc-pkcs11.so", "01497", "2", - "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; DigiDoc4J.main(parameters); } @@ -275,7 +284,7 @@ public void createsContainerAndAddsFileWithoutMimeType() throws Exception { this.systemExit.expectSystemExitWithStatus(2); String file = this.getFileBy("bdoc"); String[] parameters = new String[]{"-in", file, "-add", "src/test/resources/testFiles/helper-files/test.txt", - "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; DigiDoc4J.main(parameters); } @@ -283,8 +292,8 @@ public void createsContainerAndAddsFileWithoutMimeType() throws Exception { public void createMultipleSignedContainers_whereInputDirIsFile_shouldThrowException() throws Exception { this.systemExit.expectSystemExitWithStatus(6); String[] parameters = new String[]{"-inputDir", this.testFolder.newFile("inputFolder").getPath(), - "-outputDir", this.testFolder.newFolder("outputFolder").getPath(), "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-outputDir", this.testFolder.newFolder("outputFolder").getPath(), + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; DigiDoc4J.main(parameters); } @@ -293,17 +302,17 @@ public void createMultipleSignedContainers_whereOutputDirIsFile_shouldThrowExcep String inputFolder = this.testFolder.newFolder("inputFolder").getPath(); String outputFolder = this.testFolder.newFile("outputFolder").getPath(); this.systemExit.expectSystemExitWithStatus(6); - String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; DigiDoc4J.main(parameters); } @Test public void createMultipleSignedContainers_withEmptyInputDir_shouldDoNothing() throws Exception { this.systemExit.expectSystemExitWithStatus(0); - String[] parameters = new String[]{"-inputDir", this.testFolder.newFolder("inputFolder").getPath(), "-outputDir", - this.testFolder.newFolder("outputFolder").getPath(), "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + String[] parameters = new String[]{"-inputDir", this.testFolder.newFolder("inputFolder").getPath(), + "-outputDir", this.testFolder.newFolder("outputFolder").getPath(), + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; DigiDoc4J.main(parameters); } @@ -314,8 +323,8 @@ public void createMultipleSignedContainers_withinInputDirectory() throws Excepti FileUtils.writeStringToFile(new File(inputFolder, "firstDoc.txt"), "Hello daddy"); FileUtils.writeStringToFile(new File(inputFolder, "secondDoc.pdf"), "John Matrix"); FileUtils.writeStringToFile(new File(inputFolder, "thirdDoc.acc"), "Major General Franklin Kirby"); - String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Assert.assertEquals(3, new File(outputFolder).listFiles().length); TestAssert.assertFolderContainsFile(outputFolder, "firstDoc.bdoc"); @@ -329,8 +338,9 @@ public void createMultipleSignedContainers_withoutOutputDirectory_shouldCreateOu String outputFolder = new File(inputFolder, "notExistingOutputFolder").getPath(); FileUtils.writeStringToFile(new File(inputFolder, "firstDoc.txt"), "Hello daddy"); FileUtils.writeStringToFile(new File(inputFolder, "secondDoc.pdf"), "John Matrix"); - String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test", "-type", "BDOC"}; + String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-type", "BDOC"}; TestDigiDoc4JUtil.call(parameters); File folder = new File(outputFolder); Assert.assertTrue(folder.exists()); @@ -347,8 +357,8 @@ public void createMultipleSignedContainers_withExistingSavedContainers_shouldThr String outputFolder = this.testFolder.newFolder("outputFolder").getPath(); FileUtils.writeStringToFile(new File(inputFolder, "firstDoc.txt"), "Hello daddy"); FileUtils.writeStringToFile(new File(outputFolder, "firstDoc.bdoc"), "John Matrix"); - String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, "-pkcs12", - "src/test/resources/testFiles/p12/signout.p12", "test"}; + String[] parameters = new String[]{"-inputDir", inputFolder, "-outputDir", outputFolder, + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; DigiDoc4J.main(parameters); } @@ -359,7 +369,7 @@ public void createSignedContainer_forEachFile_withInputDirectoryAndMimeType() th FileUtils.writeStringToFile(new File(inputFolder, "firstDoc.txt"), "Hello daddy"); FileUtils.writeStringToFile(new File(inputFolder, "secondDoc.pdf"), "John Matrix"); String[] parameters = new String[]{"-inputDir", inputFolder, "-mimeType", "text/xml", "-outputDir", outputFolder, - "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", "test"}; + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD}; TestDigiDoc4JUtil.call(parameters); Container container = ContainerOpener.open(new File(outputFolder, "firstDoc.bdoc").getPath()); Assert.assertEquals("text/xml", container.getDataFiles().get(0).getMediaType()); @@ -857,9 +867,10 @@ private void assertExtractingDataFile(String containerPath, String fileToExtract public void createAndValidateDetachedXades() throws Exception { String xadesSignaturePath = "singatures0.xml"; - String[] parameters = new String[]{"-xades", "-digFile", "test.txt", - "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg", "text/plain", "-pkcs12", "src/test/resources/testFiles/p12/signout.p12", - "test", "-sigOutputPath", xadesSignaturePath}; + String[] parameters = new String[]{"-xades", + "-digFile", "test.txt", "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg", "text/plain", + "-pkcs12", TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD, + "-sigOutputPath", xadesSignaturePath}; TestDigiDoc4JUtil.call(parameters); parameters = new String[]{"-xades", "-digFile", "test.txt", diff --git a/digidoc4j/src/test/java/org/digidoc4j/signers/ExternalSignerTest.java b/digidoc4j/src/test/java/org/digidoc4j/signers/ExternalSignerTest.java index cf3f74cc5..747661481 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/signers/ExternalSignerTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/signers/ExternalSignerTest.java @@ -53,7 +53,7 @@ public byte[] sign(DigestAlgorithm digestAlgorithm, byte[] dataToSign) { @Ignore // TODO Fix me when possible public void testAsyncSigning() { Container container = this.createNonEmptyContainer(); - DataToSign dataToSign = SignatureBuilder.aSignature(container).withSigningCertificate(this.pkcs12SignatureToken.getCertificate()). + DataToSign dataToSign = SignatureBuilder.aSignature(container).withSigningCertificate(pkcs12SignatureToken.getCertificate()). buildDataToSign(); String containerFile = this.getFileBy("bin"); String dataToSignFile = this.getFileBy("bin"); @@ -72,14 +72,14 @@ public void testAsyncSigning() { */ private SignatureToken getExternalSignatureToken() { - return new ExternalSigner(this.pkcs12SignatureToken.getCertificate()) { + return new ExternalSigner(pkcs12SignatureToken.getCertificate()) { @Override public byte[] sign(DigestAlgorithm digestAlgorithm, byte[] dataToSign) { try { KeyStore keyStore = KeyStore.getInstance("PKCS12"); - try (FileInputStream stream = new FileInputStream("src/test/resources/testFiles/p12/signout.p12")) { - keyStore.load(stream, "test".toCharArray()); + try (FileInputStream stream = new FileInputStream(TestSigningUtil.TEST_PKI_CONTAINER)) { + keyStore.load(stream, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD.toCharArray()); } PrivateKey privateKey = (PrivateKey) keyStore.getKey("1", "test".toCharArray()); return TestSigningUtil.encrypt(String.format("NONEwith%s", privateKey.getAlgorithm()), privateKey, TestSigningUtil.addPadding(dataToSign)); diff --git a/digidoc4j/src/test/java/org/digidoc4j/signers/PKCS12SignatureTokenTest.java b/digidoc4j/src/test/java/org/digidoc4j/signers/PKCS12SignatureTokenTest.java index c99ced38a..2bf148cca 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/signers/PKCS12SignatureTokenTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/signers/PKCS12SignatureTokenTest.java @@ -1,68 +1,97 @@ /* DigiDoc4J library -* -* This software is released under either the GNU Library General Public -* License (see LICENSE.LGPL). -* -* Note that the only valid version of the LGPL license as far as this -* project is concerned is the original GNU Library General Public License -* Version 2.1, February 1999 -*/ + * + * This software is released under either the GNU Library General Public + * License (see LICENSE.LGPL). + * + * Note that the only valid version of the LGPL license as far as this + * project is concerned is the original GNU Library General Public License + * Version 2.1, February 1999 + */ package org.digidoc4j.signers; -import java.security.cert.CertificateEncodingException; - import org.apache.commons.codec.binary.Base64; import org.digidoc4j.AbstractTest; import org.digidoc4j.DigestAlgorithm; import org.digidoc4j.X509Cert; +import org.digidoc4j.exceptions.InvalidKeyException; +import org.digidoc4j.test.util.TestSigningUtil; import org.junit.Assert; import org.junit.Test; +import java.security.cert.CertificateEncodingException; + public class PKCS12SignatureTokenTest extends AbstractTest { @Test public void getCertificate() throws CertificateEncodingException { - X509Cert x509Cert = new X509Cert(this.pkcs12SignatureToken.getCertificate()); - Assert.assertEquals("MIIFrjCCA5agAwIBAgIQUwvkG7xZfERXDit8E7z6DDANBgkqhkiG9w0BAQsFADBr" + + X509Cert x509Cert = new X509Cert(pkcs12SignatureToken.getCertificate()); + Assert.assertEquals("MIIGuDCCBKCgAwIBAgIQbsALi4xUxPdggr2EPjoVJjANBgkqhkiG9w0BAQsFADBr" + "MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1" + "czEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxHzAdBgNVBAMMFlRFU1Qgb2YgRVNU" + - "RUlELVNLIDIwMTUwHhcNMTYwNDEzMTEyMDI4WhcNMjEwNDEyMjA1OTU5WjCBtDEL" + - "MAkGA1UEBhMCRUUxDzANBgNVBAoMBkVTVEVJRDEaMBgGA1UECwwRZGlnaXRhbCBz" + - "aWduYXR1cmUxMTAvBgNVBAMMKMW9w5VSSU7DnFfFoEtZLE3DhFLDnC1Mw5bDllos" + - "MTE0MDQxNzY4NjUxFzAVBgNVBAQMDsW9w5VSSU7DnFfFoEtZMRYwFAYDVQQqDA1N" + - "w4RSw5wtTMOWw5ZaMRQwEgYDVQQFEwsxMTQwNDE3Njg2NTCCASIwDQYJKoZIhvcN" + - "AQEBBQADggEPADCCAQoCggEBAJrWrja4BY6nlDXf/46So37NcJoDAB8d6pZr2XxM" + - "4cCv3MqAKAuf8oew38jc+/20oBiMo9bSWfTrjCtunuyJxBi6/xX1SwXqXpCIcAeA" + - "tL8SA4NRuWQGEFxGRJtPUNpzVkiIBI5u+yENpxvGFOW7777u0E7E3p/Jx6Y6HflI" + - "CQPm48zjzeBytJ+m6v6EdObnOpeJtusaZ+Yg/hmrCRRgJeRtnjJIw5LmLrjqm185" + - "BFtgwFH0J8iAr18FSua5yLP343s4vZx8np1NqmdJrlHt5IjX2D3+QAObJmh/U+id" + - "oNdThlJlst/cj5/y496vR+PhSWIWzqv//xYH41qIkXDjD+UCAwEAAaOCAQIwgf8w" + - "CQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCBkAwOwYDVR0gBDQwMjAwBgkrBgEEAc4f" + - "AwEwIzAhBggrBgEFBQcCARYVaHR0cHM6Ly93d3cuc2suZWUvY3BzMB0GA1UdDgQW" + - "BBQ27kyYhup5RKLxTM1gxY+BDz/N0jAiBggrBgEFBQcBAwQWMBQwCAYGBACORgEB" + - "MAgGBgQAjkYBBDAfBgNVHSMEGDAWgBRJwPJEOWXVm0Y7DThgg7HWLSiGpjBBBgNV" + - "HR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNrLmVlL2NybHMvZXN0ZWlkL3Rlc3Rf" + - "ZXN0ZWlkMjAxNS5jcmwwDQYJKoZIhvcNAQELBQADggIBAHUUiGcIgXB3INd78mGF" + - "yIz+u8+TLPON0va0mRuugy1TEH0eWZqNhv2+7vvzd8CLoOp4aHrUwvx7zGaND/bO" + - "w4dC1dO5zsXh1EziNAfaNqzYP2QQ4BckqZeGl0+d7OVyP5/HgZOYI90qYLvkjWSn" + - "eSFXZ2BN8Jku6l0dUnhsQqCoLKl0j4F+1u+GwC9pjzm2aVoYRs3CcNgkAa1O3SKK" + - "9PXpz/chFE1dfvT8xPagroVkzDCZ4o6Rp+8OPBPYacQhdIH6DyagPcbdKz1S0EC8" + - "q+7qm1C8bM05oyYfkoBLU6afgRGHcpRMFQRBnsu7o1LQIMsRF5dWWTqL4FLLw6iF" + - "exZA6z3HMilu+yolLxURaD3oWMcWzLKi0Ic88T8LNyz5ksWDDZXAoso0ZDTAh/Da" + - "FEdeQs9MnOkGzrvswrEG2MUs33XHhp988TWgRQGAJU/JZQR057I/UxfikYRhZ5oM" + - "7qPBy4oDh3VlhMsY5yHuK400Xi202xoXVS+VG33xB7KCvbwuemZSlVewxTX0ZJg5" + - "qTcwIXRMlsWffqyVWpnxjnvWmqO01nrbgjlpBAbDDT2R/JXPOjVpgjhQGEmNmVj3" + - "OvfjvLlXXP7CZ4Vxwxy0aBPPvVHoyWjFycsqm4EFGSGkcB17NcP3dlj7ZwloBobg" + - "ittrqXcLf8qik7sGgHnaa7Cc", + "RUlELVNLIDIwMTUwIBcNMjEwNDIzMTIyODUyWhgPMjAzMDEyMTcyMzU5NTlaMIGf" + + "MQswCQYDVQQGEwJFRTE9MDsGA1UEAww0T+KAmUNPTk5Fxb0txaBVU0xJSyBURVNU" + + "TlVNQkVSLE1BUlkgw4ROTiw2MDAwMTAxMzczOTEnMCUGA1UEBAweT+KAmUNPTk5F" + + "xb0txaBVU0xJSyBURVNUTlVNQkVSMRIwEAYDVQQqDAlNQVJZIMOETk4xFDASBgNV" + + "BAUTCzYwMDAxMDEzNzM5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA" + + "r8Gtz4AS8HoY2UpUvD9/OxJzymnvSTR5LKcG7+rLdXszEgdyRCy0sHg1yRseZgXu" + + "XQsAG/IGKQFUOBND6LAD2Puv+wk4HenB7EZmeiDQzdKGE3CoRz+UU+zz8EqQTzZi" + + "l85R7kK1oDi3b1RtB4flELSQ38ufeOFAli97K2hhYGVtPDOcJIbz4jej4UqQnY80" + + "Ma+5niQxsN9pf2W/Fe2r7TMtqmo+aKbaWMr3uLESbPGpiffetcWnllmLQR2lcx2w" + + "aHXp3XeUQXHBbtO0oypaxpgDTcRBLH3ZGuElj0KGfXqRaO6dwOjjHG5G8+Tzvy/2" + + "pvGuqbr9RvcH3QMmG1mEswIDAQABo4ICHzCCAhswCQYDVR0TBAIwADAOBgNVHQ8B" + + "Af8EBAMCBkAwdQYDVR0gBG4wbDBfBgorBgEEAc4fAwEDMFEwHgYIKwYBBQUHAgIw" + + "EgwQT25seSBmb3IgVEVTVElORzAvBggrBgEFBQcCARYjaHR0cHM6Ly93d3cuc2su" + + "ZWUvcmVwb3NpdG9vcml1bS9DUFMwCQYHBACL7EABAjAdBgNVHQ4EFgQUNGA6HJQi" + + "W4kukHbhN6CmD0Js1McwgYoGCCsGAQUFBwEDBH4wfDAIBgYEAI5GAQEwCAYGBACO" + + "RgEEMFEGBgQAjkYBBTBHMEUWP2h0dHBzOi8vc2suZWUvZW4vcmVwb3NpdG9yeS9j" + + "b25kaXRpb25zLWZvci11c2Utb2YtY2VydGlmaWNhdGVzLxMCRU4wEwYGBACORgEG" + + "MAkGBwQAjkYBBgEwHwYDVR0jBBgwFoAUScDyRDll1ZtGOw04YIOx1i0ohqYwgYMG" + + "CCsGAQUFBwEBBHcwdTAsBggrBgEFBQcwAYYgaHR0cDovL2FpYS5kZW1vLnNrLmVl" + + "L2VzdGVpZDIwMTUwRQYIKwYBBQUHMAKGOWh0dHBzOi8vc2suZWUvdXBsb2FkL2Zp" + + "bGVzL1RFU1Rfb2ZfRVNURUlELVNLXzIwMTUuZGVyLmNydDA0BgNVHR8ELTArMCmg" + + "J6AlhiNodHRwczovL2Muc2suZWUvdGVzdF9lc3RlaWQyMDE1LmNybDANBgkqhkiG" + + "9w0BAQsFAAOCAgEAn5yOThHC3o+qywote9HYZz6TgGUin606KONrUcbsP9UMZwKF" + + "HhQBAZE9ycJ3iOIKtEk0VlH5vwL0MvyY26VyHgkprozEcX5OCQKBCTn/ZKR+IIXQ" + + "wNT0ZadQHTAuCLidHH9bI4/CofTWtr6udYezmQs7FIXbcazQ6cgkb937HulVHt4x" + + "IDZ8kp9oUaqbpUfCSu5zOspQRM2ih0MshPmZvkS9qeFgbkTD0D+RPccxV7jjHCbH" + + "xjHzYNFrq2JJuKacxx/OR12KGKOtcGlYjFxWl18MJ/n3tvoEcWaXKtPZ+BmStbPH" + + "RFb29fkSIWtEzFRSbbLYeHkC53m8lWQ4kXhMJ10aZs9nXRVJ0I4/wMjZTpO6lMkq" + + "Exm77nyycxPv3glJWssFp5LEKgJKxWt2aT9ihHypqEPVjBZGfppFOJT81gxLLF0k" + + "MVxnRqpNbi/1thY5IIxFgGzxIHJlIMuw/HECMJ+/n19dF+Z8tqCoxhNxEQm409jR" + + "v6/RsRhtQ5IIY0PR8eL5xzwgET5BWy5AjUtzGeQsEiywY9+kNfLgv0GQsdfiyhyG" + + "z5oX/8t9AlntTTLpUdWRs4IU3M1yLV2qxc/zAyXRZYJ5nbkwg1oR3wttTYcQ+uFk" + + "0qCoYsLHPmNmFGYZrt00lbulpieIS/YGdFmdtQn7vip/y7LOGEU02m84Lpo=", Base64.encodeBase64String(x509Cert.getX509Certificate().getEncoded())); } @Test public void sign() { //TODO know expected value - byte[] expected = new byte[]{40, -84, -43, -95, -8, 46, -27, -2, 41, 80, -96, -74, 125, 37, -11, 85, -22, 64, -87, 122, 41, -29, 91, -35, 104, 60, 86, -98, -65, -101, 81, 74, -10, 35, -24, -115, -14, 115, -58, -53, -28, -53, 47, -82, 74, -21, 88, -111, -31, 47, 112, 71, 41, -32, 120, 119, 109, 34, -96, 124, -61, -5, 112, 114, 122, 1, 30, -105, 112, 67, 116, -32, -44, -123, -43, 26, 63, -28, -41, 82, -79, -32, 98, 93, 20, -76, -94, 105, 40, -95, -1, -97, -33, 88, 31, 92, -115, -114, 118, -94, 3, 126, -25, -100, -84, 72, -84, 51, -122, -59, -72, 0, 123, 68, -116, 91, -105, 7, 81, -106, 10, 58, -39, 53, 109, -48, -121, 4, -111, 32, -127, -74, -3, -73, -57, -12, 114, 126, -20, -40, 76, -58, 119, -108, 85, -124, 97, -55, -82, -120, -94, -40, -10, -96, -60, 29, 84, 55, 12, 77, 27, -117, -3, 84, 39, -24, -66, -89, -5, 51, -64, -53, -16, -43, -53, 63, -59, -32, 48, 82, -85, -124, -107, -85, 43, 37, 62, -63, 42, -8, 86, -79, 42, -119, -37, 30, 6, -71, 30, -63, 98, 109, 56, 74, 69, -14, -44, 104, 86, -87, 37, 109, 91, 59, -58, 33, 81, -69, -50, -82, 121, 69, -99, 18, 51, -63, 116, -56, -26, 96, -81, -17, -106, -57, 45, -15, 11, -39, -24, 121, -59, -38, 83, -3, 21, -104, -102, 116, 44, 108, -7, 79, -49, -106, 28, -82}; - byte[] actual = this.pkcs12SignatureToken.sign(DigestAlgorithm.SHA512, new byte[]{0x41}); + byte[] expected = new byte[]{-127,-10,88,-97,-31,-28,99,55,-33,-83,10,-18,8,-83,-34,123,75,60,27,34,-41,3,62,-100,89,15,6,-38,82,-52,51,71,-14,-66,-92,88,-107,79,-22,125,3,-44,-11,112,110,60,-28,-77,54,-49,7,89,-66,-43,116,-67,83,-31,-34,119,101,-68,-44,105,-58,114,-2,-99,80,98,-21,-72,88,1,-103,-15,85,39,-50,-17,-63,-121,123,-121,-66,59,-27,-59,-6,-55,-32,-55,43,-126,43,-39,-33,2,-22,40,-18,-15,-83,26,-3,14,-29,-20,36,-17,-119,95,-63,99,111,109,25,-96,13,115,-113,75,48,61,-34,-75,86,18,76,-48,-96,-111,68,-58,-104,110,99,-19,125,34,14,3,82,-48,39,-4,35,-104,-43,-58,-35,-83,-18,38,-87,19,9,-74,114,-24,-33,69,76,105,125,78,108,-84,43,104,-95,124,38,-125,33,108,-122,-121,-104,113,98,17,-81,-91,-99,80,-123,58,6,108,-59,-41,-33,-39,98,125,112,-58,120,-32,-99,51,-29,-50,30,-22,94,11,113,-107,-119,-49,-52,83,-83,-101,-52,108,92,91,-78,17,-78,-42,71,2,-125,73,112,-72,79,51,2,-95,-88,54,-32,77,99,-76,60,-2,-90,100,50,101,-58,48,-30,-119,-76,-63,-21,-55,-112,76}; + byte[] actual = pkcs12SignatureToken.sign(DigestAlgorithm.SHA512, new byte[]{0x41}); Assert.assertArrayEquals(expected, actual); } + @Test + public void closeSignatureTokenWhenSigning() { + this.expectedException.expect(InvalidKeyException.class); + this.expectedException.expectMessage("Private key entry is missing. Connection may be closed."); + PKCS12SignatureToken pkcs12SignatureToken = new PKCS12SignatureToken(TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD.toCharArray()); + + Assert.assertNotNull(pkcs12SignatureToken.sign(DigestAlgorithm.SHA512, new byte[]{0x41})); + pkcs12SignatureToken.close(); + pkcs12SignatureToken.sign(DigestAlgorithm.SHA512, new byte[]{0x41}); + } + + @Test + public void closeSignatureTokenWhenAskingCertificate() { + this.expectedException.expect(InvalidKeyException.class); + this.expectedException.expectMessage("Private key entry is missing. Connection may be closed."); + PKCS12SignatureToken pkcs12SignatureToken = new PKCS12SignatureToken(TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD.toCharArray()); + Assert.assertNotNull(pkcs12SignatureToken.getCertificate()); + pkcs12SignatureToken.close(); + pkcs12SignatureToken.getCertificate(); + } + + } diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/MockConfigurableDataLoader.java b/digidoc4j/src/test/java/org/digidoc4j/test/MockConfigurableDataLoader.java new file mode 100644 index 000000000..cec84cd7f --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/test/MockConfigurableDataLoader.java @@ -0,0 +1,96 @@ +package org.digidoc4j.test; + +import eu.europa.esig.dss.model.DSSException; +import eu.europa.esig.dss.spi.client.http.DataLoader; +import eu.europa.esig.dss.spi.exception.DSSDataLoaderMultipleException; +import eu.europa.esig.dss.utils.Utils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class MockConfigurableDataLoader implements DataLoader { + + @FunctionalInterface + public interface Getter { + byte[] get(String url, Boolean refresh) throws DSSException; + } + + @FunctionalInterface + public interface Poster { + byte[] post(String url, byte[] content) throws DSSException; + } + + private Getter getter = (url, refresh) -> { + throw new UnsupportedOperationException("GET operations not configured"); + }; + private Poster poster = (url, content) -> { + throw new UnsupportedOperationException("POST operations not configured"); + }; + + @Override + public byte[] get(String url) throws DSSException { + return getter.get(url, null); + } + + @Override + public DataAndUrl get(List urlStrings) throws DSSException { + if (Utils.isCollectionEmpty(urlStrings)) { + throw new DSSException("Cannot process the GET call. List of URLs is empty!"); + } else { + Map exceptions = new HashMap(); + for (String url : urlStrings) { + try { + byte[] bytes = getter.get(url, null); + if (!Utils.isArrayEmpty(bytes)) { + return new DataAndUrl(bytes, url); + } + } catch (Exception e) { + exceptions.put(url, e); + } + } + throw new DSSDataLoaderMultipleException(exceptions); + } + } + + @Override + public byte[] get(String url, boolean refresh) throws DSSException { + return getter.get(url, refresh); + } + + @Override + public byte[] post(String url, byte[] content) throws DSSException { + return poster.post(url, content); + } + + @Override + public void setContentType(String contentType) {} + + public Getter getGetter() { + return getter; + } + + public void setGetter(Getter getter) { + this.getter = Objects.requireNonNull(getter); + } + + public MockConfigurableDataLoader withGetter(Getter getter) { + setGetter(getter); + return this; + } + + public Poster getPoster() { + return poster; + } + + public void setPoster(Poster poster) { + this.poster = Objects.requireNonNull(poster); + } + + public MockConfigurableDataLoader withPoster(Poster poster) { + setPoster(poster); + return this; + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/MockSignatureBuilder.java b/digidoc4j/src/test/java/org/digidoc4j/test/MockSignatureBuilder.java index b2d3a3818..6a0f85601 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/test/MockSignatureBuilder.java +++ b/digidoc4j/src/test/java/org/digidoc4j/test/MockSignatureBuilder.java @@ -21,6 +21,8 @@ import org.digidoc4j.exceptions.SignerCertificateRequiredException; import org.digidoc4j.impl.SignatureFinalizer; +import java.util.ArrayList; + /** * Used in unit tests. */ @@ -31,7 +33,7 @@ public class MockSignatureBuilder extends SignatureBuilder { @Override public DataToSign buildDataToSign() throws SignerCertificateRequiredException, ContainerWithoutFilesException { - SignatureFinalizer signatureFinalizer = new SignatureFinalizer(null, null, null) { + SignatureFinalizer signatureFinalizer = new SignatureFinalizer(new ArrayList<>(), null, null) { @Override public Signature finalizeSignature(byte[] signatureValue) { finalizedSignatureValue = signatureValue; diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/TestAssert.java b/digidoc4j/src/test/java/org/digidoc4j/test/TestAssert.java index 42cf51e90..325ffb79f 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/test/TestAssert.java +++ b/digidoc4j/src/test/java/org/digidoc4j/test/TestAssert.java @@ -10,31 +10,16 @@ package org.digidoc4j.test; -import static org.apache.commons.lang3.StringUtils.isEmpty; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.regex.Pattern; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - +import eu.europa.esig.dss.model.DSSDocument; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.digidoc4j.Configuration; import org.digidoc4j.Container; import org.digidoc4j.Signature; import org.digidoc4j.exceptions.DigiDoc4JException; +import org.digidoc4j.impl.SKOnlineOCSPSource; import org.digidoc4j.impl.SkDataLoader; import org.digidoc4j.impl.asic.asice.AsicESignature; -import org.digidoc4j.impl.SKOnlineOCSPSource; import org.digidoc4j.impl.asic.xades.XadesSignature; import org.hamcrest.CoreMatchers; import org.junit.Assert; @@ -43,10 +28,18 @@ import org.w3c.dom.Document; import org.xml.sax.SAXException; -import eu.europa.esig.dss.model.DSSDocument; -import eu.europa.esig.dss.service.http.commons.CommonsDataLoader; -import eu.europa.esig.dss.service.http.proxy.ProxyConfig; -import eu.europa.esig.dss.service.http.proxy.ProxyProperties; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.regex.Pattern; /** * Created by Janar Rahumeel (CGI Estonia) @@ -86,7 +79,7 @@ public static void assertContainsError(String error, List er return; } } - Assert.assertFalse(String.format("Expected <%s> was not found", error), true); + Assert.fail(String.format("Expected <%s> was not found", error)); } public static void assertSignatureMetadataContainsFileName(Signature signature, String fileName) { @@ -118,25 +111,15 @@ public static void assertSaveAsStream(Container container) throws IOException { TestAssert.assertContainerStream(container.saveAsStream()); } - public static void assertHTTPProxyIsConfigured(CommonsDataLoader loader, String proxyHost, int proxyPort) { - ProxyConfig config = loader.getProxyConfig(); - Assert.assertNotNull(config); - ProxyProperties httpProperties = config.getHttpProperties(); - ProxyProperties httpsProperties = config.getHttpsProperties(); - Assert.assertEquals(proxyHost, httpProperties.getHost()); - Assert.assertEquals(proxyPort, httpProperties.getPort()); - Assert.assertEquals(null, httpsProperties.getHost()); - Assert.assertEquals(0, httpsProperties.getPort()); - } - - public static void assertProxyCredentialsAreUnset(CommonsDataLoader loader) { - ProxyConfig config = loader.getProxyConfig(); - ProxyProperties httpProperties = config.getHttpProperties(); - ProxyProperties httpsProperties = config.getHttpsProperties(); - Assert.assertTrue(isEmpty(httpProperties.getUser())); - Assert.assertTrue(isEmpty(httpsProperties.getUser())); - Assert.assertTrue(isEmpty(httpProperties.getPassword())); - Assert.assertTrue(isEmpty(httpsProperties.getPassword())); + public static void assertSuppressed(Throwable throwable, Class suppressedType, String... suppressedMessages) { + Throwable[] suppressedList = throwable.getSuppressed(); + Assert.assertNotNull(suppressedList); + Assert.assertEquals(suppressedMessages.length, suppressedList.length); + for (int i = 0; i < suppressedMessages.length; ++i) { + Assert.assertNotNull(suppressedList[i]); + Assert.assertTrue(suppressedType.isInstance(suppressedList[i])); + Assert.assertEquals(suppressedMessages[i], suppressedList[i].getMessage()); + } } /* diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/TestLog.java b/digidoc4j/src/test/java/org/digidoc4j/test/TestLog.java new file mode 100644 index 000000000..8bd290b2e --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/test/TestLog.java @@ -0,0 +1,58 @@ +package org.digidoc4j.test; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.Appender; +import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; +import org.hamcrest.collection.IsIterableContainingInOrder; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class TestLog { + + private final Appender mockedAppender; + + public TestLog() { + this("org.digidoc4j"); + } + + public TestLog(Class loggerClass) { + this(loggerClass.getCanonicalName()); + } + + @SuppressWarnings("unchecked") + public TestLog(String loggerName) { + mockedAppender = (Appender) Mockito.mock(Appender.class); + Logger logger = (Logger) LoggerFactory.getLogger(loggerName); + logger.addAppender(mockedAppender); + } + + public void verifyLogInOrder(Matcher... matchers) { + verifyLogInOrder(logEvent -> true, matchers); + } + + @SuppressWarnings("unchecked") + public void verifyLogInOrder(Predicate logEventFilter, Matcher... matchers) { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(ILoggingEvent.class); + Mockito.verify(mockedAppender, Mockito.atLeast(1)).doAppend(argumentCaptor.capture()); + List listOfMessages = argumentCaptor.getAllValues().stream().filter(logEventFilter).map(ILoggingEvent::getFormattedMessage).collect(Collectors.toList()); + // NB: Make sure the correct overload of IsIterableContainingInOrder.contains is called, otherwise the matchers are wrapped twice and matching won't work! + MatcherAssert.assertThat(listOfMessages, IsIterableContainingInOrder.contains((Matcher[]) matchers)); + } + + public void verifyLogEmpty() { + Mockito.verifyNoInteractions(mockedAppender); + } + + @SuppressWarnings("unchecked") + public void reset() { + Mockito.reset(mockedAppender); + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/util/TestCertificateUtil.java b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestCertificateUtil.java new file mode 100644 index 000000000..cb6f3e503 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestCertificateUtil.java @@ -0,0 +1,64 @@ +package org.digidoc4j.test.util; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.util.Date; +import java.util.Objects; +import java.util.concurrent.ThreadLocalRandom; + +public final class TestCertificateUtil { + + public static JcaX509v3CertificateBuilder createX509v3CertificateBuilder( + X500Name issuer, BigInteger serial, Instant notBefore, Instant notAfter, X500Name subject, PublicKey publicKey + ) { + Objects.requireNonNull(notAfter, "NotAfter not provided"); + Objects.requireNonNull(subject, "Subject not provided"); + Objects.requireNonNull(publicKey, "Public key not provided"); + return new JcaX509v3CertificateBuilder( + (issuer != null) ? issuer : subject, + (serial != null) ? serial : generateSerial(64), + Date.from(notBefore != null ? notBefore : Instant.now()), + Date.from(notAfter), + subject, + publicKey + ); + } + + public static ContentSigner createCertificateSigner(PrivateKey privateKey, String signatureAlgorithm) { + try { + return new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(privateKey); + } catch (OperatorCreationException e) { + throw new IllegalStateException("Failed to create certificate signer", e); + } + } + + public static X509Certificate toX509Certificate(X509CertificateHolder x509CertificateHolder) { + try { + return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(x509CertificateHolder); + } catch (CertificateException e) { + throw new IllegalStateException("Failed to convert certificate", e); + } + } + + public static BigInteger generateSerial(int size) { + byte[] serialBytes = new byte[size]; + ThreadLocalRandom.current().nextBytes(serialBytes); + return new BigInteger(1, serialBytes); + } + + private TestCertificateUtil() {} + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/util/TestDataBuilderUtil.java b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestDataBuilderUtil.java index b26678d16..13bea7489 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/test/util/TestDataBuilderUtil.java +++ b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestDataBuilderUtil.java @@ -49,7 +49,7 @@ public static Container createContainerWithFile(String dataFilePath) { } public static Container createContainerWithFile(String dataFilePath, String mimeType) { - return ContainerBuilder.aContainer().withConfiguration(new Configuration(Configuration.Mode.TEST)). + return ContainerBuilder.aContainer(Container.DocumentType.BDOC).withConfiguration(new Configuration(Configuration.Mode.TEST)). withDataFile(dataFilePath, mimeType).build(); } @@ -96,7 +96,7 @@ private static Container populateContainerBuilderWithFile(ContainerBuilder build private static SignatureBuilder prepareDataToSign(Container container) { return SignatureBuilder.aSignature(container).withSignatureDigestAlgorithm(DigestAlgorithm.SHA256). - withSignatureProfile(SignatureProfile.LT_TM).withSigningCertificate(TestSigningUtil.getSigningCertificate()); + withSignatureProfile(SignatureProfile.LT).withSigningCertificate(TestSigningUtil.getSigningCertificate()); } public static File createTestFile(TemporaryFolder testFolder) throws IOException { diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/util/TestKeyPairUtil.java b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestKeyPairUtil.java new file mode 100644 index 000000000..9f7b03821 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestKeyPairUtil.java @@ -0,0 +1,96 @@ +package org.digidoc4j.test.util; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPrivateKeySpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; +import java.util.Objects; + +public final class TestKeyPairUtil { + + private static final String EC_KEY_ALGORITHM = "ECDSA"; + + public static AsymmetricCipherKeyPair generateEcKeyPair(ECDomainParameters ecDomainParameters) { + ECKeyGenerationParameters ecKeyGenerationParameters = new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom()); + ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator(); + ecKeyPairGenerator.init(ecKeyGenerationParameters); + return ecKeyPairGenerator.generateKeyPair(); + } + + public static AsymmetricCipherKeyPair generateEcKeyPair(String ecCurveName) { + ECNamedCurveParameterSpec ecNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec(ecCurveName); + Objects.requireNonNull(ecNamedCurveParameterSpec, "No such EC curve found: " + ecCurveName); + ECDomainParameters ecDomainParameters = ECUtil.getDomainParameters(null, ecNamedCurveParameterSpec); + return generateEcKeyPair(ecDomainParameters); + } + + public static PrivateKey toPrivateKey(ECPrivateKeyParameters ecPrivateKeyParameters) { + try { + ECParameterSpec ecParameterSpec = toECParameterSpec(ecPrivateKeyParameters.getParameters()); + ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(ecPrivateKeyParameters.getD(), ecParameterSpec); + return createKeyFactoryForEC().generatePrivate(ecPrivateKeySpec); + } catch (InvalidKeySpecException e) { + throw new IllegalStateException("Failed to convert to private key", e); + } + } + + public static PublicKey toPublicKey(ECPublicKeyParameters ecPublicKeyParameters) { + try { + ECParameterSpec ecParameterSpec = toECParameterSpec(ecPublicKeyParameters.getParameters()); + ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(ecPublicKeyParameters.getQ(), ecParameterSpec); + return createKeyFactoryForEC().generatePublic(ecPublicKeySpec); + } catch (InvalidKeySpecException e) { + throw new IllegalStateException("Failed to convert to private key", e); + } + } + + private static KeyFactory createKeyFactoryForEC() { + try { + return KeyFactory.getInstance(EC_KEY_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException("Unsupported key algorithm: " + EC_KEY_ALGORITHM, e); + } catch (NoSuchProviderException e) { + throw new IllegalStateException("Unsupported provider: " + BouncyCastleProvider.PROVIDER_NAME, e); + } + } + + private static ECParameterSpec toECParameterSpec(ECDomainParameters ecDomainParameters) { + ECCurve curve = ecDomainParameters.getCurve(); + ECPoint g = ecDomainParameters.getG(); + BigInteger n = ecDomainParameters.getN(); + BigInteger h = ecDomainParameters.getH(); + byte[] seed = ecDomainParameters.getSeed(); + + if (ecDomainParameters instanceof ECNamedDomainParameters) { + ECNamedDomainParameters ecNamedDomainParameters = (ECNamedDomainParameters) ecDomainParameters; + String name = ECUtil.getCurveName(ecNamedDomainParameters.getName()); + return new ECNamedCurveParameterSpec(name, curve, g, n, h, seed); + } else { + return new ECParameterSpec(curve, g, n, h, seed); + } + } + + private TestKeyPairUtil() {} + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/test/util/TestSigningUtil.java b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestSigningUtil.java index bb94e6496..aa7845438 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/test/util/TestSigningUtil.java +++ b/digidoc4j/src/test/java/org/digidoc4j/test/util/TestSigningUtil.java @@ -28,8 +28,8 @@ public class TestSigningUtil { - public static final String TEST_PKI_CONTAINER = "src/test/resources/testFiles/p12/signout.p12"; - public static final String TEST_PKI_CONTAINER_PASSWORD = "test"; + public static final String TEST_PKI_CONTAINER = "src/test/resources/testFiles/p12/sign_RSA_from_TEST_of_ESTEIDSK2015.p12"; + public static final String TEST_PKI_CONTAINER_PASSWORD = "1234"; public static final String TEST_ECC_PKI_CONTAINER = "src/test/resources/testFiles/p12/MadDogOY.p12"; public static final String TEST_ECC_PKI_CONTAINER_PASSWORD = "test"; public static final X509Certificate SIGN_CERT = TestSigningUtil.toX509Certificate("-----BEGIN CERTIFICATE-----\r\n" + diff --git a/digidoc4j/src/test/java/org/digidoc4j/utils/KeyStoreDocumentTest.java b/digidoc4j/src/test/java/org/digidoc4j/utils/KeyStoreDocumentTest.java new file mode 100644 index 000000000..970ffd776 --- /dev/null +++ b/digidoc4j/src/test/java/org/digidoc4j/utils/KeyStoreDocumentTest.java @@ -0,0 +1,287 @@ +package org.digidoc4j.utils; + +import org.apache.commons.io.IOUtils; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.digidoc4j.AbstractTest; +import org.digidoc4j.test.TestLog; +import org.digidoc4j.test.util.TestCertificateUtil; +import org.digidoc4j.test.util.TestKeyPairUtil; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.time.Instant; +import java.time.Period; +import java.time.temporal.ChronoUnit; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; + +public class KeyStoreDocumentTest extends AbstractTest { + + private static final String KEYSTORE_TYPE = "PKCS12"; + private static final String KEYSTORE_PASSWORD = "Passw0rd"; + private static final String KEYSTORE_EXTENSION = ".p12"; + + private TestLog testLog; + + @BeforeClass + public static void setUpStatic() { + Security.addProvider(new BouncyCastleProvider()); + } + + @Override + protected void before() { + testLog = new TestLog(KeyStoreDocument.class); + } + + @Test + public void testKeyStoreFailsToLoadWhenNotExisting() { + String nonExistingPath = new File(testFolder.getRoot(), "non-existing-keystore" + KEYSTORE_EXTENSION).getPath(); + Duration minValidationInterval = Duration.ofMinutes(1L); + Period maxWarningPeriod = Period.ofDays(1); + + IllegalArgumentException caughtException = assertThrows( + IllegalArgumentException.class, + () -> new KeyStoreDocument(nonExistingPath, KEYSTORE_TYPE, KEYSTORE_PASSWORD, minValidationInterval, maxWarningPeriod) + ); + + Assert.assertEquals("Resource not found: " + nonExistingPath, caughtException.getMessage()); + testLog.verifyLogEmpty(); + } + + @Test + public void testKeyStoreFailsToParseOnInvalidKeystoreType() { + String keyStorePath = "classpath:testFiles/truststores/empty-truststore.p12"; + String invalidKeyStoreType = "INVALID"; + Duration minValidationInterval = Duration.ofMinutes(1L); + Period maxWarningPeriod = Period.ofDays(1); + + IllegalStateException caughtException = assertThrows( + IllegalStateException.class, + () -> new KeyStoreDocument(keyStorePath, invalidKeyStoreType, KEYSTORE_PASSWORD, minValidationInterval, maxWarningPeriod) + ); + + Assert.assertEquals("Failed to create key-store of type: " + invalidKeyStoreType, caughtException.getMessage()); + testLog.verifyLogEmpty(); + } + + @Test + public void testKeyStoreFailsToParseOnInvalidKeystorePassword() { + String keyStorePath = "classpath:testFiles/truststores/empty-truststore.p12"; + String invalidKeyStorePassword = "Inval1d"; + Duration minValidationInterval = Duration.ofMinutes(1L); + Period maxWarningPeriod = Period.ofDays(1); + + IllegalStateException caughtException = assertThrows( + IllegalStateException.class, + () -> new KeyStoreDocument(keyStorePath, KEYSTORE_TYPE, invalidKeyStorePassword, minValidationInterval, maxWarningPeriod) + ); + + Assert.assertEquals("Failed to load key-store from: " + keyStorePath, caughtException.getMessage()); + testLog.verifyLogEmpty(); + } + + @Test + public void testInitialKeystoreValidationWithWarningPeriod() throws Exception { + Instant now = Instant.now(); + + Map certificates = new LinkedHashMap<>(); + certificates.put("expired-day", createTestCertificate("CN=EXPIRED-DAY", now.minus(Period.ofDays(2)), now.minus(Period.ofDays(1)))); + certificates.put("expired-minute", createTestCertificate("CN=EXPIRED-MINUTE", now.minus(Duration.ofMinutes(2L)), now.minus(Duration.ofMinutes(1L)))); + for (int i = 1; i < 9; ++i) { + certificates.put("about-to-expire-" + i, createTestCertificate("CN=ABOUT-TO-EXPIRE-" + i, now, now.plus(Period.ofDays(i)))); + } + certificates.put("about-to-expire-minute", createTestCertificate("CN=ABOUT-TO-EXPIRE-MINUTE", now, now.plus(Period.ofDays(9)).minus(Duration.ofMinutes(1L)))); + certificates.put("still-time-minute", createTestCertificate("CN=STILL-TIME-MINUTE", now, now.plus(Period.ofDays(9)).plus(Duration.ofMinutes(1L)))); + certificates.put("still-time-plenty", createTestCertificate("CN=STILL-TIME-PLENTY", now, now.plus(Period.ofDays(365)))); + + File keyStoreFile = createTestKeyStore(certificates); + String keyStorePath = keyStoreFile.getCanonicalPath(); + Duration minValidationInterval = Duration.ofMinutes(5L); + Period maxWarningPeriod = Period.ofDays(9); + + KeyStoreDocument keyStoreDocument = new KeyStoreDocument(keyStorePath, KEYSTORE_TYPE, KEYSTORE_PASSWORD, minValidationInterval, maxWarningPeriod); + + String expiredTemplate = "Certificate from \"%s\" has already expired (%s) - alias: \"%s\"; subject: \"%s\""; + String expiringTemplate = "Certificate from \"%s\" expires (%s) in about %d day(s) - alias: \"%s\"; subject: \"%s\""; + testLog.verifyLogInOrder( + Matchers.equalTo(String.format(expiredTemplate, keyStorePath, now.minus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS), "expired-day", "CN=EXPIRED-DAY")), + Matchers.equalTo(String.format(expiredTemplate, keyStorePath, now.minus(Duration.ofMinutes(1L)).truncatedTo(ChronoUnit.SECONDS), "expired-minute", "CN=EXPIRED-MINUTE")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS), 8, "about-to-expire-1", "CN=ABOUT-TO-EXPIRE-1")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(2)).truncatedTo(ChronoUnit.SECONDS), 7, "about-to-expire-2", "CN=ABOUT-TO-EXPIRE-2")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(3)).truncatedTo(ChronoUnit.SECONDS), 6, "about-to-expire-3", "CN=ABOUT-TO-EXPIRE-3")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(4)).truncatedTo(ChronoUnit.SECONDS), 5, "about-to-expire-4", "CN=ABOUT-TO-EXPIRE-4")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(5)).truncatedTo(ChronoUnit.SECONDS), 4, "about-to-expire-5", "CN=ABOUT-TO-EXPIRE-5")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(6)).truncatedTo(ChronoUnit.SECONDS), 3, "about-to-expire-6", "CN=ABOUT-TO-EXPIRE-6")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(7)).truncatedTo(ChronoUnit.SECONDS), 2, "about-to-expire-7", "CN=ABOUT-TO-EXPIRE-7")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(8)).truncatedTo(ChronoUnit.SECONDS), 1, "about-to-expire-8", "CN=ABOUT-TO-EXPIRE-8")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(9)).minus(Duration.ofMinutes(1L)).truncatedTo(ChronoUnit.SECONDS), 0, "about-to-expire-minute", "CN=ABOUT-TO-EXPIRE-MINUTE")) + ); + assertKeyStoreDocumentContent(keyStoreFile, keyStoreDocument); + } + + @Test + public void testInitialKeystoreValidationWithWarningDuration() throws Exception { + Instant now = Instant.now(); + + Map certificates = new LinkedHashMap<>(); + certificates.put("expired-day", createTestCertificate("CN=EXPIRED-DAY", now.minus(Period.ofDays(2)), now.minus(Period.ofDays(1)))); + certificates.put("expired-minute", createTestCertificate("CN=EXPIRED-MINUTE", now.minus(Duration.ofMinutes(2L)), now.minus(Duration.ofMinutes(1L)))); + for (int i = 1; i < 6; ++i) { + certificates.put("about-to-expire-" + i, createTestCertificate("CN=ABOUT-TO-EXPIRE-" + i, now, now.plus(Duration.ofMinutes(i)))); + } + certificates.put("still-time-minute", createTestCertificate("CN=STILL-TIME-MINUTE", now, now.plus(Duration.ofMinutes(7L)))); + certificates.put("still-time-plenty", createTestCertificate("CN=STILL-TIME-PLENTY", now, now.plus(Period.ofDays(365)))); + + File keyStoreFile = createTestKeyStore(certificates); + String keyStorePath = keyStoreFile.getCanonicalPath(); + Duration minValidationInterval = Duration.ofMinutes(5L); + Duration maxWarningPeriod = Duration.ofMinutes(6L); + + KeyStoreDocument keyStoreDocument = new KeyStoreDocument(keyStorePath, KEYSTORE_TYPE, KEYSTORE_PASSWORD, minValidationInterval, maxWarningPeriod); + + String expiredTemplate = "Certificate from \"%s\" has already expired (%s) - alias: \"%s\"; subject: \"%s\""; + String expiringTemplate = "Certificate from \"%s\" expires (%s) in about 0 day(s) - alias: \"%s\"; subject: \"%s\""; + testLog.verifyLogInOrder( + Matchers.equalTo(String.format(expiredTemplate, keyStorePath, now.minus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS), "expired-day", "CN=EXPIRED-DAY")), + Matchers.equalTo(String.format(expiredTemplate, keyStorePath, now.minus(Duration.ofMinutes(1L)).truncatedTo(ChronoUnit.SECONDS), "expired-minute", "CN=EXPIRED-MINUTE")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Duration.ofMinutes(1L)).truncatedTo(ChronoUnit.SECONDS), "about-to-expire-1", "CN=ABOUT-TO-EXPIRE-1")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Duration.ofMinutes(2L)).truncatedTo(ChronoUnit.SECONDS), "about-to-expire-2", "CN=ABOUT-TO-EXPIRE-2")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Duration.ofMinutes(3L)).truncatedTo(ChronoUnit.SECONDS), "about-to-expire-3", "CN=ABOUT-TO-EXPIRE-3")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Duration.ofMinutes(4L)).truncatedTo(ChronoUnit.SECONDS), "about-to-expire-4", "CN=ABOUT-TO-EXPIRE-4")), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Duration.ofMinutes(5L)).truncatedTo(ChronoUnit.SECONDS), "about-to-expire-5", "CN=ABOUT-TO-EXPIRE-5")) + ); + assertKeyStoreDocumentContent(keyStoreFile, keyStoreDocument); + } + + @Test + public void testOpenStreamTriggersValidationWhenPreviousValidationHasExpired() throws Exception { + Instant now = Instant.now(); + + Map certificates = new LinkedHashMap<>(); + certificates.put("expired", createTestCertificate("CN=EXPIRED", now.minus(Period.ofDays(2)), now.minus(Period.ofDays(1)))); + certificates.put("expiring", createTestCertificate("CN=EXPIRING", now, now.plus(Period.ofDays(1)))); + certificates.put("fine", createTestCertificate("CN=FINE", now, now.plus(Period.ofDays(5)))); + + File keyStoreFile = createTestKeyStore(certificates); + String keyStorePath = keyStoreFile.getCanonicalPath(); + Duration minValidationInterval = Duration.ZERO; + Period maxWarningPeriod = Period.ofDays(2); + + KeyStoreDocument keyStoreDocument = new KeyStoreDocument(keyStorePath, KEYSTORE_TYPE, KEYSTORE_PASSWORD, minValidationInterval, maxWarningPeriod); + + String expiredTemplate = "Certificate from \"%s\" has already expired (%s) - alias: \"expired\"; subject: \"CN=EXPIRED\""; + String expiringTemplate = "Certificate from \"%s\" expires (%s) in about 1 day(s) - alias: \"expiring\"; subject: \"CN=EXPIRING\""; + testLog.verifyLogInOrder( + Matchers.equalTo(String.format(expiredTemplate, keyStorePath, now.minus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS))), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS))) + ); + + testLog.reset(); + InputStream stream = keyStoreDocument.openStream(); + stream.close(); + + testLog.verifyLogInOrder( + Matchers.equalTo(String.format(expiredTemplate, keyStorePath, now.minus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS))), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS))) + ); + } + + @Test + public void testOpenStreamDoesNotTriggerValidationWhenPreviousValidationHasNotExpired() throws Exception { + Instant now = Instant.now(); + + Map certificates = new LinkedHashMap<>(); + certificates.put("expired", createTestCertificate("CN=EXPIRED", now.minus(Period.ofDays(2)), now.minus(Period.ofDays(1)))); + certificates.put("expiring", createTestCertificate("CN=EXPIRING", now, now.plus(Period.ofDays(1)))); + certificates.put("fine", createTestCertificate("CN=FINE", now, now.plus(Period.ofDays(5)))); + + File keyStoreFile = createTestKeyStore(certificates); + String keyStorePath = keyStoreFile.getCanonicalPath(); + Duration minValidationInterval = Duration.ofMinutes(10L); + Period maxWarningPeriod = Period.ofDays(2); + + KeyStoreDocument keyStoreDocument = new KeyStoreDocument(keyStorePath, KEYSTORE_TYPE, KEYSTORE_PASSWORD, minValidationInterval, maxWarningPeriod); + + String expiredTemplate = "Certificate from \"%s\" has already expired (%s) - alias: \"expired\"; subject: \"CN=EXPIRED\""; + String expiringTemplate = "Certificate from \"%s\" expires (%s) in about 1 day(s) - alias: \"expiring\"; subject: \"CN=EXPIRING\""; + testLog.verifyLogInOrder( + Matchers.equalTo(String.format(expiredTemplate, keyStorePath, now.minus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS))), + Matchers.equalTo(String.format(expiringTemplate, keyStorePath, now.plus(Period.ofDays(1)).truncatedTo(ChronoUnit.SECONDS))) + ); + + testLog.reset(); + InputStream stream = keyStoreDocument.openStream(); + stream.close(); + + testLog.verifyLogEmpty(); + } + + private File createTestKeyStore(Map certificates) throws Exception { + KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE); + keyStore.load(null, KEYSTORE_PASSWORD.toCharArray()); + for (Map.Entry entry : certificates.entrySet()) { + keyStore.setCertificateEntry(entry.getKey(), entry.getValue()); + } + File keyStoreFile = testFolder.newFile(UUID.randomUUID().toString() + KEYSTORE_EXTENSION); + try (OutputStream outputStream = new FileOutputStream(keyStoreFile)) { + keyStore.store(outputStream, KEYSTORE_PASSWORD.toCharArray()); + } + return keyStoreFile; + } + + private static X509Certificate createTestCertificate(String subjectDN, Instant notBefore, Instant notAfter) throws Exception { + AsymmetricCipherKeyPair keyPair = TestKeyPairUtil.generateEcKeyPair("secp384r1"); + PrivateKey signingKey = TestKeyPairUtil.toPrivateKey((ECPrivateKeyParameters) keyPair.getPrivate()); + PublicKey publicKey = TestKeyPairUtil.toPublicKey((ECPublicKeyParameters) keyPair.getPublic()); + X500Name subjectDnX500Name = new X500Name(subjectDN); + + JcaX509v3CertificateBuilder certificateBuilder = TestCertificateUtil.createX509v3CertificateBuilder( + null, null, notBefore, notAfter, subjectDnX500Name, publicKey + ); + + ContentSigner signer = TestCertificateUtil.createCertificateSigner(signingKey, "SHA512withECDSA"); + return TestCertificateUtil.toX509Certificate(certificateBuilder.build(signer)); + } + + private static X509Certificate createTestCertificate(String subjectDN, Instant notAfter) throws Exception { + return createTestCertificate(subjectDN, Instant.now(), notAfter); + } + + private void assertKeyStoreDocumentContent(File sourceFile, KeyStoreDocument keyStoreDocument) throws Exception { + byte[] expectedContent = Files.readAllBytes(sourceFile.toPath()); + + try (InputStream in = keyStoreDocument.openStream()) { + byte[] actualContent = IOUtils.toByteArray(in); + Assert.assertArrayEquals(expectedContent, actualContent); + } + + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + keyStoreDocument.writeTo(out); + byte[] actualContent = out.toByteArray(); + Assert.assertArrayEquals(expectedContent, actualContent); + } + } + +} diff --git a/digidoc4j/src/test/java/org/digidoc4j/utils/PolicyUtilsTest.java b/digidoc4j/src/test/java/org/digidoc4j/utils/PolicyUtilsTest.java index d5c218816..578c6dfd7 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/utils/PolicyUtilsTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/utils/PolicyUtilsTest.java @@ -31,7 +31,7 @@ public void createBDocSignaturePolicy() { assertEquals("OIDAsURN", policy.getQualifier().getValue()); assertEquals(DigestAlgorithm.SHA256, policy.getDigestAlgorithm()); assertEquals("https://www.sk.ee/repository/bdoc-spec21.pdf", policy.getSpuri()); - assertThat(Base64.decodeBase64("7pudpH4eXlguSZY2e/pNbKzGsq+fu//woYL1SZFws1A="), IsEqual.equalTo(policy.getDigestValue())); + assertThat(Base64.decodeBase64("3Tl1oILSvOAWomdI9VeWV6IA/32eSXRUri9kPEz1IVs="), IsEqual.equalTo(policy.getDigestValue())); } @Test diff --git a/digidoc4j/src/test/java/org/digidoc4j/utils/TokenAlgorithmSupportTest.java b/digidoc4j/src/test/java/org/digidoc4j/utils/TokenAlgorithmSupportTest.java index ca8f2ee6c..cc97cc080 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/utils/TokenAlgorithmSupportTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/utils/TokenAlgorithmSupportTest.java @@ -24,7 +24,7 @@ public class TokenAlgorithmSupportTest { @Test public void getDefaultDigestAlgorithm_shouldReturnSha256() throws Exception { - PKCS12SignatureToken testSignatureToken = new PKCS12SignatureToken("src/test/resources/testFiles/p12/signout.p12", "test".toCharArray()); + PKCS12SignatureToken testSignatureToken = new PKCS12SignatureToken(TestSigningUtil.TEST_PKI_CONTAINER, TestSigningUtil.TEST_PKI_CONTAINER_PASSWORD.toCharArray()); DigestAlgorithm digestAlgorithm = TokenAlgorithmSupport.determineSignatureDigestAlgorithm(testSignatureToken.getCertificate()); Assert.assertEquals(DigestAlgorithm.SHA256, digestAlgorithm); } diff --git a/digidoc4j/src/test/java/org/digidoc4j/utils/ZipEntryInputStreamTest.java b/digidoc4j/src/test/java/org/digidoc4j/utils/ZipEntryInputStreamTest.java index 92ce86ed6..b33bcec6e 100644 --- a/digidoc4j/src/test/java/org/digidoc4j/utils/ZipEntryInputStreamTest.java +++ b/digidoc4j/src/test/java/org/digidoc4j/utils/ZipEntryInputStreamTest.java @@ -21,7 +21,7 @@ public class ZipEntryInputStreamTest { @Before public void setUp() { - zipEntryInputStream = new ZipEntryInputStream(zipInputStream); + zipEntryInputStream = new ZipEntryInputStream(zipInputStream, null); Mockito.verifyZeroInteractions(zipInputStream); } diff --git a/digidoc4j/src/test/resources/testFiles/certs/DEMO_OF_SK_TSA_2014.cer b/digidoc4j/src/test/resources/testFiles/certs/DEMO_OF_SK_TSA_2014.cer new file mode 100644 index 000000000..5dc31def6 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/certs/DEMO_OF_SK_TSA_2014.cer differ diff --git a/digidoc4j/src/test/resources/testFiles/certs/d-trust-ca.cer b/digidoc4j/src/test/resources/testFiles/certs/d-trust-ca.cer new file mode 100644 index 000000000..6ada7ce6e --- /dev/null +++ b/digidoc4j/src/test/resources/testFiles/certs/d-trust-ca.cer @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIIHvjCCBXagAwIBAgIDD+R2MD0GCSqGSIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCA6IDAgFAMF4xCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgxHzAdBgNVBAMTFkQtVFJVU1QgUm9vdCBDQSAzIDIwMTYxFzAVBgNVBGETDk5UUkRFLUhSQjc0MzQ2MB4XDTE2MTAyNjA4MzYzOFoXDTMxMTAyNjA4MzY1MFowWzELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEcMBoGA1UEAxMTRC1UUlVTVCBDQSAzLTEgMjAxNjEXMBUGA1UEYRMOTlRSREUtSFJCNzQzNDYwggIgMAsGCSqGSIb3DQEBCgOCAg8AMIICCgKCAgEA0Qf6buWosCBXDA9QBiJjHLYSAYgKOatoXaJMuclKoa1vNueQEKupz5Cw1u5oiyQIlgflJAyUHGNPv4IkpK01QfUFaNYKJswZ+nb3DK0aalbwghzZOBmYJn1qUNVD/G8ZJ4EcFrcHQp78Cuu4UpImNSjeA8Deg3X9i0NDyd0DR/jUjU9Ufwypf+NbklUH7YYfzdgUonKgaPkVr99tjK7lnmUE0nQWa/FHQLFmx40txQbpFst/W6sLw3Dxk9VniZOeZO5/nY6hxP3wPr/H12nCWuHfbQBl0H3ImqQFxvSdHGWaCOwousH+sywrlFaUv3Rtohq9ZVrAaFw3MAOXI9VpZBRh0gXx/tAtGnazQWBbShTGqgXAV8Gb/bHpIZiHA6iip87Sh+cHMUVYbdpowc7svirH5AvsY+5z/kbcmZNS796hvFPf0svJp+CUW8+H8atsCp5WKS7bzCE/bWjhlIUXjDlX8Czac2N9brUaJ/elyhL+iSq0z/Lrx/iH4SlkmZy5bdxGd9vdYaTTHineTVVydtr/gwwrXpE92vKntLYQ2BDLLU6JKCzCRPJntdLCdr8lDY9hDMF+EMaw9EIYmNqdRl/UEldzoJQSf1oIGxNCb+K2tFKl9iL+9f6N5k9mblbF9j0uKkyLUHZJnRhWoaOEyRR/Uyy+62cvCfcnCpjofsMCAwEAAaOCAigwggIkMB8GA1UdIwQYMBaAFNzAEr2IPWMTjDSr286LMsQRTl3nMIGJBggrBgEFBQcBAQR9MHswMgYIKwYBBQUHMAGGJmh0dHA6Ly9yb290LWNhLTMtMjAxNi5vY3NwLmQtdHJ1c3QubmV0MEUGCCsGAQUFBzAChjlodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NnaS1iaW4vRC1UUlVTVF9Sb290X0NBXzNfMjAxNi5jcnQwcQYDVR0gBGowaDAJBgcEAIvsQAECMFsGCysGAQQBpTQCgRYBMEwwSgYIKwYBBQUHAgEWPmh0dHA6Ly93d3cuZC10cnVzdC5uZXQvaW50ZXJuZXQvZmlsZXMvRC1UUlVTVF9Sb290X1BLSV9DUFMucGRmMIG+BgNVHR8EgbYwgbMwdKByoHCGbmxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQvQ049RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDE2LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MDugOaA3hjVodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18yMDE2LmNybDAdBgNVHQ4EFgQU++3frUvwJbXSet2fmh0vbQlQIccwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwPQYJKoZIhvcNAQEKMDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMCAUADggIBAG030a1pW3Ze5g2lc2xNcDybRUNcCCe6tzzBYLZ2e4iM5MmwTjbUKfmLrJwsHLON5zCzcNqZQv9vubTEJ+BheP4n8KS2hvhSYsxeqyQCn+NCwounhvsHw9H8dF+yWsSN8ltMF33fYNRdI5ZYnO2oCGcqRb71MnK2lkVOXySYYMLi0P6+0NotCvlLsM0tuH50ahuDZk/1A+dVcATwLWB4LVvH3lP6FADCjMJ7Rq2lgGzJ60BAE/VuAi2FmS1XFOJOXHxUsE9auwOtlg0kUhI52ohrQ6KoJslB0Ze/v2ihMju2wY+85Vz5cKAt8rZRZcvJg8IN7AFOwoDvlp2/ejF7CXuIAf6BracK/hVsVMVVaeef4FwtXBrtIlZPQoMj369ZVBnPp0b5zwiYeVBjkQyZjBXTNwEQLZQc8fNN49GRVJV/FGjnd5XR6umz+GBjKXPcupPKVX2qoU5tviOr90xYHYTAo3mFJ+9HreVW2URl/GSJ/wN2Isk9RJlDwVqTpo8NoRPvutMfRyUkw/y297iGdRszmPfMjNQV9u6Nhv+7CzXcRHKsRK/LNN1F8jtMkFo7YCULYI5UK9staE/F+IKe04eBdo4D7bIIgb+zQ7RhgTvQdWtNu4cp1Opx+yJDHY/7k8yXtX5A5XcWuaQLn4vcx7lSs9YswY4998kMliPtWfpA +-----END CERTIFICATE----- \ No newline at end of file diff --git a/digidoc4j/src/test/resources/testFiles/certs/sameCN_first.crt b/digidoc4j/src/test/resources/testFiles/certs/sameCN_first.crt new file mode 100644 index 000000000..c852b5df3 --- /dev/null +++ b/digidoc4j/src/test/resources/testFiles/certs/sameCN_first.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDZjCCAk4CAQEwDQYJKoZIhvcNAQEFBQAwgbQxCzAJBgNVBAYTAkVFMQ8wDQYD +VQQKDAZFU1RFSUQxGjAYBgNVBAsMEWRpZ2l0YWwgc2lnbmF0dXJlMTEwLwYDVQQD +DCjFvcOVUklOw5xXxaBLWSxNw4RSw5wtTMOWw5ZaLDExNDA0MTc2ODY1MRcwFQYD +VQQEDA7FvcOVUklOw5xXxaBLWTEWMBQGA1UEKgwNTcOEUsOcLUzDlsOWWjEUMBIG +A1UEBRMLMTE0MDQxNzY4NjUwHhcNMjEwMzAyMTU0NTExWhcNMjIwMzAyMTU0NTEx +WjA9MQswCQYDVQQGEwJFRTELMAkGA1UECAwCRUUxEDAOBgNVBAcMB1RhbGxpbm4x +DzANBgNVBAMMBnVuaXF1ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMXl9pqRAPmXnNuh5m31SeF0/kddTWiAHpw68A1I0OMr/1xE0eXnH+/JXpSzfEtB +8+q9Ar5EEIe1AUJm/puSNGlQNiZFGKk44xXcya1R0pkwHJbk24ChJl9af6YwFjNn +nBWZmphCMLfxm5tlfrCRuBJ4+c6gjjgI4wem7WZnGuTr4cqELugp1uf+3yAFBrbC +zI0ltseUs93pizrT1t2SGR7TtT+HrdlscD3XZmlMRm4U7Dh8/0GeC/jJuTo0HViS +AL/+VaXu3t2WwQy/CerdqY4EFkRcMDOhgJwukzHH3XbtbwkfMho0dqVd/HO+Qw90 +dTaDLKduKtsYyJcuYbJeye8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAHxYA1aEJ +ILGSRa77tHpUvGRQkGmce0Cl+LgYJIuaAYKkQaIXLpb1Su6ge/AYHBUt9vtstHyl +wpX3DUCBfazeduzPToawaMM+4pzVNYaoZfGQbfWGyQuMU5KckGA+LMUkLMnS0SqP +BBGcziWRjVATSYXz82/dtRIQ+Tf9xy96Y0fGDo892LxizWVIqCPwxmeJfMUd9VAD +Rj5mbKuRCEeTTJii/2D2C+/xB3USbXVgKiaRhWUob2IWv5aJcA5ZjNhIGleaQ+VH +ECRkw8UfK8u1BIQs3LnnI4v8fMp4n828l8HhSU5tgnP8qJtzN3+KS+oAsum5KanS +g4/UDKIX2RZeaw== +-----END CERTIFICATE----- diff --git a/digidoc4j/src/test/resources/testFiles/certs/sameCN_first_child.crt b/digidoc4j/src/test/resources/testFiles/certs/sameCN_first_child.crt new file mode 100644 index 000000000..f891461c0 --- /dev/null +++ b/digidoc4j/src/test/resources/testFiles/certs/sameCN_first_child.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC7TCCAdUCAQEwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UEBhMCRUUxCzAJBgNV +BAgMAkVFMRAwDgYDVQQHDAdUYWxsaW5uMQ8wDQYDVQQDDAZ1bmlxdWUwHhcNMjEw +MzAzMDk1NzUzWhcNNDAwNTAyMDk1NzUzWjA8MQswCQYDVQQGEwJFRTELMAkGA1UE +CAwCRUUxEDAOBgNVBAcMB1RhbGxpbm4xDjAMBgNVBAMMBWNoaWxkMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq39ZVGGN1dFrfiL1veEApHeG80v6WJti +Da8nRmCfyElV+WLp0nwLA1lh54dbVqmlzBmiPgV2redQk4v8Zr1mrWfYRBMHLahU +wI70plMjwVgRN1mDpMnw2lRBjW90I5ViHe70l6IzQBoLUkFM0PI794loCkpnh0DL +dkrdNzdfid647UjNShiHZ5p6Bo69uoicIrLbl9zoKrowZnZhs+nT1tObE4Xbs3lB +akKMc9LboLJ3H5DgIsJ7uzcs5qYLu6giz5MEqms7h86AhbGpms2FymK/qlU+9PRL +/jXKDM9kk7OvfUWtqrlMBgdTVSxWG50csvPcSh+pzSdIZQwJkRPYPwIDAQABMA0G +CSqGSIb3DQEBBQUAA4IBAQAD+GTgvBzLstT3E44pC7b/CCXliBz6FO4JY5fP3AbP +BN3qqpW7+t6rEhSbD07Nv9iEiv9zoCyJR0N48RhGnlcTO4sLHt3TLh7k0JdYRa2K +Q7J9dAxRQTV5NGnyd2qGi1UFTARUrQIHJqFyYP+LMtrok1x1/l2d1mOkaP47v3xj +alY3skVMVN8sYngh8oYdNNneGZY5F5mIqSVId4tIQpWHA169qMnJBbwdKQg/XOC6 +lRXDObaH2mqvQK5L+q0goilS+eUtbAHJmm1e/YM1JT1KSwsXx65ZfLMu/Q2mhR0B +OQ7Qp5GLFuBt+ec5+0kBzX5Z6ZvrGo4JCeinGdkhxM39 +-----END CERTIFICATE----- diff --git a/digidoc4j/src/test/resources/testFiles/certs/sameCN_second.crt b/digidoc4j/src/test/resources/testFiles/certs/sameCN_second.crt new file mode 100644 index 000000000..1dd09018b --- /dev/null +++ b/digidoc4j/src/test/resources/testFiles/certs/sameCN_second.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDZjCCAk4CAQEwDQYJKoZIhvcNAQEFBQAwgbQxCzAJBgNVBAYTAkVFMQ8wDQYD +VQQKDAZFU1RFSUQxGjAYBgNVBAsMEWRpZ2l0YWwgc2lnbmF0dXJlMTEwLwYDVQQD +DCjFvcOVUklOw5xXxaBLWSxNw4RSw5wtTMOWw5ZaLDExNDA0MTc2ODY1MRcwFQYD +VQQEDA7FvcOVUklOw5xXxaBLWTEWMBQGA1UEKgwNTcOEUsOcLUzDlsOWWjEUMBIG +A1UEBRMLMTE0MDQxNzY4NjUwHhcNMjEwMzAyMTU0NzA0WhcNMjIwMzAyMTU0NzA0 +WjA9MQswCQYDVQQGEwJFRTELMAkGA1UECAwCRUUxEDAOBgNVBAcMB1RhbGxpbm4x +DzANBgNVBAMMBnVuaXF1ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALyLQUPv4a+32H09BM9gDG67degcf24ckvjnpVqxznMNFx9+RBfTFOt9XlpiDroy +wUxoV0siHOcNs9pQ4gvzCd6nxuT5ue5Fmsfn3bmPpWsYqvfiZ+qAFQv3dkjy1F0g +aZ44FzPa2LgzS3o8KZmOfYJFSq0Nv8PF7iFNTZR5VTyW0BJfZVnbz+T0ASihUcoO +UV2k5iT8XXMChiwxgwp1n75FOq+QecDtZWsvMTrrQcWdkeUc0baGU0ncKcnZjiHm +Ap0szezwEN+QWCTKtpKb7MoR5+/ra7MVJ71Tl6AFlgZl3c7UgG44UTvbG0wBb0a5 +keGH7Vy7xjaqDHyfZFeuWSMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAKrIlqpR4 +I3uNpX5z4xQDasLSpM7HabB0GEnYMXaxepyzhRB0daQrF++nPLb637H7lfAQlb8Q +a4RnVMdfgeSnQ/StJ9RErd9pkL5rojPUburicJebwrOaiTRbC9BDpahxj97vK8Pj +0FeoBCapbr+rsaP2QCYjGgLhHe/hPMlP97gYx1DwVtuYBcZvYADsltbhWdGpAHMB +WtTNlsjdVvj+afZPmxD1ROQIIMQM9YfOdMiqI5k5E9UU3j3YVJuend9mwZf+fQzn +9E28Fe1agLtQCQWmlmDbcm4kIiJP4F0YpTqL0rDm+xEXxceQ9BZsUNzItQn9kt5g +BVY91vKFBT7uKw== +-----END CERTIFICATE----- diff --git a/digidoc4j/src/test/resources/testFiles/certs/sign_RSA_from_TEST_of_ESTEIDSK2015.pem b/digidoc4j/src/test/resources/testFiles/certs/sign_RSA_from_TEST_of_ESTEIDSK2015.pem new file mode 100644 index 000000000..bbce0b991 --- /dev/null +++ b/digidoc4j/src/test/resources/testFiles/certs/sign_RSA_from_TEST_of_ESTEIDSK2015.pem @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +MIIGuDCCBKCgAwIBAgIQbsALi4xUxPdggr2EPjoVJjANBgkqhkiG9w0BAQsFADBr +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEXMBUGA1UEYQwOTlRSRUUtMTA3NDcwMTMxHzAdBgNVBAMMFlRFU1Qgb2YgRVNU +RUlELVNLIDIwMTUwIBcNMjEwNDIzMTIyODUyWhgPMjAzMDEyMTcyMzU5NTlaMIGf +MQswCQYDVQQGEwJFRTE9MDsGA1UEAww0T+KAmUNPTk5Fxb0txaBVU0xJSyBURVNU +TlVNQkVSLE1BUlkgw4ROTiw2MDAwMTAxMzczOTEnMCUGA1UEBAweT+KAmUNPTk5F +xb0txaBVU0xJSyBURVNUTlVNQkVSMRIwEAYDVQQqDAlNQVJZIMOETk4xFDASBgNV +BAUTCzYwMDAxMDEzNzM5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +r8Gtz4AS8HoY2UpUvD9/OxJzymnvSTR5LKcG7+rLdXszEgdyRCy0sHg1yRseZgXu +XQsAG/IGKQFUOBND6LAD2Puv+wk4HenB7EZmeiDQzdKGE3CoRz+UU+zz8EqQTzZi +l85R7kK1oDi3b1RtB4flELSQ38ufeOFAli97K2hhYGVtPDOcJIbz4jej4UqQnY80 +Ma+5niQxsN9pf2W/Fe2r7TMtqmo+aKbaWMr3uLESbPGpiffetcWnllmLQR2lcx2w +aHXp3XeUQXHBbtO0oypaxpgDTcRBLH3ZGuElj0KGfXqRaO6dwOjjHG5G8+Tzvy/2 +pvGuqbr9RvcH3QMmG1mEswIDAQABo4ICHzCCAhswCQYDVR0TBAIwADAOBgNVHQ8B +Af8EBAMCBkAwdQYDVR0gBG4wbDBfBgorBgEEAc4fAwEDMFEwHgYIKwYBBQUHAgIw +EgwQT25seSBmb3IgVEVTVElORzAvBggrBgEFBQcCARYjaHR0cHM6Ly93d3cuc2su +ZWUvcmVwb3NpdG9vcml1bS9DUFMwCQYHBACL7EABAjAdBgNVHQ4EFgQUNGA6HJQi +W4kukHbhN6CmD0Js1McwgYoGCCsGAQUFBwEDBH4wfDAIBgYEAI5GAQEwCAYGBACO +RgEEMFEGBgQAjkYBBTBHMEUWP2h0dHBzOi8vc2suZWUvZW4vcmVwb3NpdG9yeS9j +b25kaXRpb25zLWZvci11c2Utb2YtY2VydGlmaWNhdGVzLxMCRU4wEwYGBACORgEG +MAkGBwQAjkYBBgEwHwYDVR0jBBgwFoAUScDyRDll1ZtGOw04YIOx1i0ohqYwgYMG +CCsGAQUFBwEBBHcwdTAsBggrBgEFBQcwAYYgaHR0cDovL2FpYS5kZW1vLnNrLmVl +L2VzdGVpZDIwMTUwRQYIKwYBBQUHMAKGOWh0dHBzOi8vc2suZWUvdXBsb2FkL2Zp +bGVzL1RFU1Rfb2ZfRVNURUlELVNLXzIwMTUuZGVyLmNydDA0BgNVHR8ELTArMCmg +J6AlhiNodHRwczovL2Muc2suZWUvdGVzdF9lc3RlaWQyMDE1LmNybDANBgkqhkiG +9w0BAQsFAAOCAgEAn5yOThHC3o+qywote9HYZz6TgGUin606KONrUcbsP9UMZwKF +HhQBAZE9ycJ3iOIKtEk0VlH5vwL0MvyY26VyHgkprozEcX5OCQKBCTn/ZKR+IIXQ +wNT0ZadQHTAuCLidHH9bI4/CofTWtr6udYezmQs7FIXbcazQ6cgkb937HulVHt4x +IDZ8kp9oUaqbpUfCSu5zOspQRM2ih0MshPmZvkS9qeFgbkTD0D+RPccxV7jjHCbH +xjHzYNFrq2JJuKacxx/OR12KGKOtcGlYjFxWl18MJ/n3tvoEcWaXKtPZ+BmStbPH +RFb29fkSIWtEzFRSbbLYeHkC53m8lWQ4kXhMJ10aZs9nXRVJ0I4/wMjZTpO6lMkq +Exm77nyycxPv3glJWssFp5LEKgJKxWt2aT9ihHypqEPVjBZGfppFOJT81gxLLF0k +MVxnRqpNbi/1thY5IIxFgGzxIHJlIMuw/HECMJ+/n19dF+Z8tqCoxhNxEQm409jR +v6/RsRhtQ5IIY0PR8eL5xzwgET5BWy5AjUtzGeQsEiywY9+kNfLgv0GQsdfiyhyG +z5oX/8t9AlntTTLpUdWRs4IU3M1yLV2qxc/zAyXRZYJ5nbkwg1oR3wttTYcQ+uFk +0qCoYsLHPmNmFGYZrt00lbulpieIS/YGdFmdtQn7vip/y7LOGEU02m84Lpo= +-----END CERTIFICATE----- diff --git a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_fail_level.xml b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_fail_level.xml index 00666e286..b950855b2 100644 --- a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_fail_level.xml +++ b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_fail_level.xml @@ -36,8 +36,6 @@ - - diff --git a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_warn_level.xml b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_warn_level.xml index c0a1b1d6d..c8eca8901 100644 --- a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_warn_level.xml +++ b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_all_warn_level.xml @@ -36,8 +36,6 @@ - - diff --git a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_version_fail.xml b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_version_fail.xml index 2ad120930..fc7b92b18 100644 --- a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_version_fail.xml +++ b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_version_fail.xml @@ -36,8 +36,6 @@ - - diff --git a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_well_signed_fail.xml b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_well_signed_fail.xml index 402b43482..be51a55f1 100644 --- a/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_well_signed_fail.xml +++ b/digidoc4j/src/test/resources/testFiles/constraints/eIDAS_test_constraint_well_signed_fail.xml @@ -36,8 +36,6 @@ - - diff --git a/digidoc4j/src/test/resources/testFiles/constraints/moved_constraint.xml b/digidoc4j/src/test/resources/testFiles/constraints/moved_constraint.xml index 25030217b..d06cb9665 100644 --- a/digidoc4j/src/test/resources/testFiles/constraints/moved_constraint.xml +++ b/digidoc4j/src/test/resources/testFiles/constraints/moved_constraint.xml @@ -36,8 +36,6 @@ - - diff --git a/digidoc4j/src/test/resources/testFiles/helper-files/empty.txt b/digidoc4j/src/test/resources/testFiles/helper-files/empty.txt new file mode 100644 index 000000000..e69de29bb diff --git a/digidoc4j/src/test/resources/testFiles/invalid-containers/NoOcspCertificateAnywhere.bdoc b/digidoc4j/src/test/resources/testFiles/invalid-containers/NoOcspCertificateAnywhere.bdoc new file mode 100644 index 000000000..5f0162fef Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/invalid-containers/NoOcspCertificateAnywhere.bdoc differ diff --git a/digidoc4j/src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLT.asice b/digidoc4j/src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLT.asice new file mode 100644 index 000000000..94164a3d2 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLT.asice differ diff --git a/digidoc4j/src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLTA.asice b/digidoc4j/src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLTA.asice new file mode 100644 index 000000000..573ecd5a4 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/invalid-containers/esteid2018signerAiaOcspLTA.asice differ diff --git a/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc b/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc new file mode 100644 index 000000000..15eb478e9 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip-1gb.bdoc differ diff --git a/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip.asics b/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip.asics new file mode 100644 index 000000000..bb1035f2a Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb-package-zip.asics differ diff --git a/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb.asice b/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb.asice new file mode 100644 index 000000000..c5a70afa7 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/invalid-containers/zip-bomb.asice differ diff --git a/digidoc4j/src/test/resources/testFiles/keystores/keystore.p12 b/digidoc4j/src/test/resources/testFiles/keystores/keystore.p12 new file mode 100644 index 000000000..5f2a1b748 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/keystores/keystore.p12 differ diff --git a/digidoc4j/src/test/resources/testFiles/keystores/truststore.p12 b/digidoc4j/src/test/resources/testFiles/keystores/truststore.p12 new file mode 100644 index 000000000..998a774fa Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/keystores/truststore.p12 differ diff --git a/digidoc4j/src/test/resources/testFiles/p12/sign_RSA_from_TEST_of_ESTEIDSK2015.p12 b/digidoc4j/src/test/resources/testFiles/p12/sign_RSA_from_TEST_of_ESTEIDSK2015.p12 new file mode 100644 index 000000000..a527c04ec Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/p12/sign_RSA_from_TEST_of_ESTEIDSK2015.p12 differ diff --git a/digidoc4j/src/test/resources/testFiles/valid-containers/NoAdditionalCertificates_LT.asice b/digidoc4j/src/test/resources/testFiles/valid-containers/NoAdditionalCertificates_LT.asice new file mode 100644 index 000000000..be7240297 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/valid-containers/NoAdditionalCertificates_LT.asice differ diff --git a/digidoc4j/src/test/resources/testFiles/valid-containers/NoAdditionalOcspCertificate.bdoc b/digidoc4j/src/test/resources/testFiles/valid-containers/NoAdditionalOcspCertificate.bdoc new file mode 100644 index 000000000..d764ce2fa Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/valid-containers/NoAdditionalOcspCertificate.bdoc differ diff --git a/digidoc4j/src/test/resources/testFiles/valid-containers/NoOcspCertificateAnywhere_LT_liveTS.asice b/digidoc4j/src/test/resources/testFiles/valid-containers/NoOcspCertificateAnywhere_LT_liveTS.asice new file mode 100644 index 000000000..3210f2d35 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/valid-containers/NoOcspCertificateAnywhere_LT_liveTS.asice differ diff --git a/digidoc4j/src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.asice b/digidoc4j/src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.asice new file mode 100644 index 000000000..753fda97d Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.asice differ diff --git a/digidoc4j/src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.bdoc b/digidoc4j/src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.bdoc new file mode 100644 index 000000000..b31909ddb Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/valid-containers/signed-container-with-empty-datafiles.bdoc differ diff --git a/digidoc4j/src/test/resources/testFiles/valid-containers/unsigned-container-with-empty-datafiles.asice b/digidoc4j/src/test/resources/testFiles/valid-containers/unsigned-container-with-empty-datafiles.asice new file mode 100644 index 000000000..710e142f4 Binary files /dev/null and b/digidoc4j/src/test/resources/testFiles/valid-containers/unsigned-container-with-empty-datafiles.asice differ diff --git a/digidoc4j/src/test/resources/testFiles/yaml-configurations/digidoc_test_conf_temp_file_max_age.yaml b/digidoc4j/src/test/resources/testFiles/yaml-configurations/digidoc_test_conf_temp_file_max_age.yaml new file mode 100644 index 000000000..fb788193c --- /dev/null +++ b/digidoc4j/src/test/resources/testFiles/yaml-configurations/digidoc_test_conf_temp_file_max_age.yaml @@ -0,0 +1 @@ +TEMP_FILE_MAX_AGE: 60 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 29e5f0280..6cb71bf25 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.digidoc4j digidoc4j-parent - 4.1.1 + 4.2.0 pom DigiDoc4J parent @@ -142,7 +142,7 @@ 1.8 1.8 1.7.30 - 1.65 + 1.68 none @@ -202,6 +202,9 @@ org.apache.maven.plugins maven-javadoc-plugin 3.2.0 + + 8 + attach-javadocs @@ -224,7 +227,7 @@ org.jacoco jacoco-maven-plugin - 0.8.6 + 0.8.7 @@ -315,7 +318,7 @@ org.owasp dependency-check-maven - 6.0.3 + 6.1.6 false false diff --git a/publish.sh b/publish.sh index e6139281d..27692305e 100755 --- a/publish.sh +++ b/publish.sh @@ -1,6 +1,6 @@ #!/bin/bash -version="4.1.1" +version="4.2.0" staging_url="https://oss.sonatype.org/service/local/staging/deploy/maven2/" repositoryId="ossrh"