/* 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 */ package org.digidoc4j; import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import static org.digidoc4j.Container.DocumentType.BDOC; import static org.digidoc4j.Container.DocumentType.DDOC; import static org.digidoc4j.ContainerBuilder.BDOC_CONTAINER_TYPE; import static org.digidoc4j.ContainerBuilder.DDOC_CONTAINER_TYPE; import static org.digidoc4j.X509Cert.SubjectName.GIVENNAME; import static org.digidoc4j.X509Cert.SubjectName.SERIALNUMBER; import static org.digidoc4j.X509Cert.SubjectName.SURNAME; import static org.digidoc4j.testutils.TestHelpers.containsErrorMessage; import static org.digidoc4j.utils.DateUtils.isAlmostNow; import static org.digidoc4j.utils.Helper.deleteFile; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.URI; import java.security.cert.CertificateEncodingException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; import org.apache.commons.codec.binary.Base64; import org.digidoc4j.exceptions.CertificateNotFoundException; import org.digidoc4j.exceptions.DigiDoc4JException; import org.digidoc4j.exceptions.NotYetImplementedException; import org.digidoc4j.impl.Certificates; import org.digidoc4j.impl.DigiDoc4JTestHelper; import org.digidoc4j.impl.bdoc.tsl.TSLCertificateSourceImpl; import org.digidoc4j.impl.ddoc.DDocFacade; import org.digidoc4j.impl.ddoc.DDocOpener; import org.digidoc4j.signers.PKCS12SignatureToken; import org.digidoc4j.testutils.TSLHelper; import org.digidoc4j.testutils.TestDataBuilder; import org.digidoc4j.testutils.TestHelpers; import org.digidoc4j.utils.Helper; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; public class SignatureTest extends DigiDoc4JTestHelper { private PKCS12SignatureToken PKCS12_SIGNER; @Rule public TemporaryFolder testFolder = new TemporaryFolder(); @Before public void setUp() throws Exception { PKCS12_SIGNER = new PKCS12SignatureToken("testFiles/signout.p12", "test".toCharArray()); } @Test public void testGetSigningCertificateForBDoc() throws Exception { Container container = ContainerOpener.open("testFiles/asics_for_testing.bdoc"); byte[] certificate = container.getSignatures().get(0).getSigningCertificate().getX509Certificate().getEncoded(); assertEquals(Certificates.SIGNING_CERTIFICATE, Base64.encodeBase64String(certificate)); } @Test public void testTimeStampCreationTimeForBDoc() throws ParseException { Container container = ContainerOpener.open("testFiles/test.asice"); Date timeStampCreationTime = container.getSignature(0).getTimeStampCreationTime(); SimpleDateFormat dateFormat = new SimpleDateFormat("MMM d yyyy H:m:s", Locale.ENGLISH); assertEquals(dateFormat.parse("Nov 17 2014 16:11:46"), timeStampCreationTime); } @Test(expected = DigiDoc4JException.class) public void testTimeStampCreationTimeForDDoc() throws ParseException { Container container = createDDoc(); container.addDataFile("testFiles/test.txt", "text/plain"); container.sign(PKCS12_SIGNER); container.getSignature(0).getTimeStampCreationTime(); container.getSignature(0).getTimeStampCreationTime(); } @Test public void testTimeStampCreationTimeForBDocWhereNotOCSP() throws ParseException, IOException { Signature signature = createSignatureFor(BDOC_CONTAINER_TYPE, SignatureProfile.B_BES); assertNull(signature.getTimeStampCreationTime()); } @Test public void testGetTimeStampTokenCertificateForBDoc() throws Exception { Signature signature = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc").getSignatures().get(0); byte[] certificate = signature.getTimeStampTokenCertificate().getX509Certificate().getEncoded(); assertEquals(Certificates.TS_CERTIFICATE, Base64.encodeBase64String(certificate)); } @Test public void testGetTimeStampTokenCertificateForBDocNoTimeStampExists() throws Exception { Signature signature = ContainerOpener.open("testFiles/asics_for_testing.bdoc").getSignatures().get(0); assertNull(signature.getTimeStampTokenCertificate()); } @Test(expected = CertificateNotFoundException.class) public void testGetSignerRolesForBDoc_OCSP_Exception() { Container container = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc"); List<Signature> signatures = container.getSignatures(); assertNull(signatures.get(0).getOCSPCertificate()); } @Test public void testGetSigningTimeForDDOC() { testGetSigningTime(DDOC); } @Test public void testGetSigningTimeForBDoc() { testGetSigningTime(BDOC); } private void testGetSigningTime(Container.DocumentType ddoc) { Signature signature = getSignature(ddoc); assertTrue(isAlmostNow(signature.getClaimedSigningTime())); } @Test public void testGetIdForDDOC() { Signature signature = getSignature(DDOC); assertEquals("S0", signature.getId()); } @Test public void testGetIdForBDoc() { Container container = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc"); assertEquals("id-99E491801522116744419D9357CEFCC5", container.getSignatures().get(0).getId()); } @Test public void testGetNonce() { Signature signature = getSignature(DDOC); assertEquals(null, Base64.encodeBase64String(signature.getOCSPNonce())); //todo correct nonce is needed } @Test public void testGetOCSPCertificateForDDoc() throws CertificateEncodingException { testGetOCSPCertificate(getSignature(DDOC)); } @Test public void testGetOCSPCertificateForBDoc() throws CertificateEncodingException { testGetOCSPCertificate(getSignature(BDOC)); } private void testGetOCSPCertificate(Signature signature) throws CertificateEncodingException { byte[] encoded = signature.getOCSPCertificate().getX509Certificate().getEncoded(); assertEquals(Certificates.OCSP_CERTIFICATE, Base64.encodeBase64String(encoded)); } @Test public void testGetSignaturePolicyForDDoc() { assertEquals("", getSignature(DDOC).getPolicy()); } @Test(expected = NotYetImplementedException.class) public void testGetSignaturePolicyForBDoc() throws Exception { Signature signature = getSignature(BDOC); assertEquals("", signature.getPolicy()); } @Test public void testGetProducedAtForDDoc() { assertTrue(isAlmostNow(getSignature(DDOC).getProducedAt())); } @Test public void testGetProducedAtForBDoc() throws ParseException { Container container = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc"); Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse("2014-07-08 12:51:16 +0000"); assertEquals(date, container.getSignatures().get(0).getProducedAt()); } @Test public void testValidationForDDoc() { assertEquals(0, getSignature(DDOC).validateSignature().getErrors().size()); } @Test public void testValidationNoParametersForDDoc() { assertEquals(0, getSignature(DDOC).validateSignature().getErrors().size()); } @Test public void testValidationForBDocDefaultValidation() throws Exception { Configuration configuration = new Configuration(Configuration.Mode.TEST); TSLHelper.addSkTsaCertificateToTsl(configuration); Container container = ContainerOpener.open("testFiles/two_signatures.bdoc", configuration); Signature signature = container.getSignatures().get(0); assertEquals(0, signature.validateSignature().getErrors().size()); signature = container.getSignatures().get(1); assertEquals(0, signature.validateSignature().getErrors().size()); } @Test public void testValidationForBDocDefaultValidationWithFailure() throws Exception { Signature signature = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc").getSignatures().get(0); List<DigiDoc4JException> errors = signature.validateSignature().getErrors(); assertTrue(containsErrorMessage(errors, "The reference data object(s) is not intact!")); assertTrue(containsErrorMessage(errors, "Signature has an invalid timestamp")); } @Test public void testValidationForBDocDefaultValidationWithOneFailing() throws Exception { Container container = ContainerOpener.open("testFiles/two_signatures_one_invalid.bdoc"); Signature signature = container.getSignatures().get(0); assertEquals(0, signature.validateSignature().getErrors().size()); signature = container.getSignatures().get(1); assertEquals(1, signature.validateSignature().getErrors().size()); ValidationResult validate = container.validate(); assertEquals(1, validate.getErrors().size()); String report = validate.getReport(); assertTrue(report.contains("Id=\"S0\" SignatureFormat=\"XAdES_BASELINE_LT\"")); assertTrue(report.contains("Id=\"S1\" SignatureFormat=\"XAdES_BASELINE_LT\"")); assertTrue(report.contains("<Indication>TOTAL_PASSED</Indication>")); assertTrue(report.contains("<Indication>INDETERMINATE</Indication>")); } @Test public void testValidationWithInvalidDDoc() { Signature signature = ContainerOpener.open("testFiles/changed_digidoc_test.ddoc").getSignatures().get(0); assertEquals(4, signature.validateSignature().getErrors().size()); } @Test public void testGetSignaturePolicyURIForDDoc() { assertNull(getSignature(DDOC).getSignaturePolicyURI()); } @Test(expected = NotYetImplementedException.class) public void testGetSignaturePolicyURIForBDoc() throws Exception { Container container = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc"); assertEquals(new URI(""), container.getSignatures().get(0).getSignaturePolicyURI()); } @Test public void testGetSignatureMethodDDoc() { assertEquals("http://www.w3.org/2000/09/xmldsig#rsa-sha1", getSignature(DDOC).getSignatureMethod()); } @Test public void testGetSignatureMethodForBDoc() { Container container = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc"); assertEquals("http://www.w3.org/2001/04/xmlenc#sha256", container.getSignatures().get(0).getSignatureMethod()); } @Test public void testGetProfileForDDoc() { assertEquals(SignatureProfile.LT_TM, getSignature(DDOC).getProfile()); } @Test public void testGetProfileForBDoc_TS() throws Exception { Container container = ContainerOpener.open("testFiles/ocsp_cert_is_not_in_tsl.bdoc"); assertEquals(SignatureProfile.LT, container.getSignatures().get(0).getProfile()); } @Test public void testGetProfileForBDoc_None() throws Exception { Container container = ContainerOpener.open("testFiles/asics_for_testing.bdoc"); assertEquals(SignatureProfile.B_BES, container.getSignatures().get(0).getProfile()); } @Test(expected = NotYetImplementedException.class) public void testGetTimeStampTokenCertificateForDDoc() { assertNull(getSignature(DDOC).getTimeStampTokenCertificate()); } @Test(expected = NotYetImplementedException.class) public void testGetNonceForBDoc() { Container container = ContainerOpener.open("testFiles/asics_for_testing.bdoc"); container.getSignatures().get(0).getOCSPNonce(); } @Test public void testGetSignaturesWhereNoSignaturePresent() throws Exception { DDocFacade container = new DDocFacade(); assertTrue(container.getSignatures().isEmpty()); } @Test public void testGetSignaturesWhereSignatureDoesNotHaveLastCertificate() throws Exception { Container container = new DDocOpener().open("testFiles/signature_without_last_certificate.ddoc"); assertEquals(0, container.getSignatures().size()); } @Test public void getSignatureXMLForBDOC() throws Exception { Container container = ContainerBuilder. aContainer(). withDataFile("testFiles/test.txt", "text/plain"). build(); Signature signature = SignatureBuilder. aSignature(container). withSignatureToken(PKCS12_SIGNER). invokeSigning(); container.addSignature(signature); container.saveAsFile("getSignatureXMLForBDOC.bdoc"); String signatureFromContainer = Helper.extractSignature("getSignatureXMLForBDOC.bdoc", 0); deleteFile("getSignatureXMLForBDOC.bdoc"); assertXMLEqual(signatureFromContainer, new String(signature.getAdESSignature())); } @Test public void signature_withoutProductionPlace_shouldNotThrowException() throws Exception { Container bdocContainer = TestDataBuilder.createContainerWithFile(testFolder, BDOC_CONTAINER_TYPE); Container ddocContainer = TestDataBuilder.createContainerWithFile(testFolder, DDOC_CONTAINER_TYPE); verifySignatureWithoutProductionPlaceDoesntThrow(bdocContainer); verifySignatureWithoutProductionPlaceDoesntThrow(ddocContainer); } @Test public void bDocBESSignature_TrustedSigningTime_shouldReturnNull() throws Exception { Signature signature = createSignatureFor(BDOC_CONTAINER_TYPE, SignatureProfile.B_BES); assertNull(signature.getTrustedSigningTime()); } @Test public void dDocBESSignature_TrustedSigningTime_shouldReturnNull() throws Exception { Signature signature = createSignatureFor(DDOC_CONTAINER_TYPE, SignatureProfile.B_BES); assertNull(signature.getTrustedSigningTime()); } @Test public void bDocTimeMarkSignature_TrustedSigningTime_shouldReturnOCSPResponseCreationTime() throws Exception { Signature signature = createSignatureFor(BDOC_CONTAINER_TYPE, SignatureProfile.LT_TM); assertNotNull(signature.getTrustedSigningTime()); assertEquals(signature.getOCSPResponseCreationTime(), signature.getTrustedSigningTime()); } @Test public void dDocTimeMarkSignature_TrustedSigningTime_shouldReturnOCSPResponseCreationTime() throws Exception { Signature signature = createSignatureFor(DDOC_CONTAINER_TYPE, SignatureProfile.LT_TM); assertNotNull(signature.getTrustedSigningTime()); assertEquals(signature.getOCSPResponseCreationTime(), signature.getTrustedSigningTime()); } @Test public void bDocTimeStampSignature_TrustedSigningTime_shouldReturnTimeStampCreationTime() throws Exception { Signature signature = createSignatureFor(BDOC_CONTAINER_TYPE, SignatureProfile.LT); assertNotNull(signature.getTrustedSigningTime()); assertEquals(signature.getTimeStampCreationTime(), signature.getTrustedSigningTime()); } @Test public void bDocLTASignature_TrustedSigningTime_shouldReturnTimeStampCreationTime() throws Exception { Signature signature = createSignatureFor(BDOC_CONTAINER_TYPE, SignatureProfile.LTA); assertNotNull(signature.getTrustedSigningTime()); assertEquals(signature.getTimeStampCreationTime(), signature.getTrustedSigningTime()); } @Test public void getSignatureSigningCertificateDetails() throws Exception { Container container = TestDataBuilder.open("testFiles/valid-containers/valid-bdoc-tm.bdoc"); Signature signature = container.getSignatures().get(0); X509Cert cert = signature.getSigningCertificate(); assertEquals("11404176865", cert.getSubjectName(SERIALNUMBER)); assertEquals("märü-lööz", cert.getSubjectName(GIVENNAME).toLowerCase()); assertEquals("žõrinüwšky", cert.getSubjectName(SURNAME).toLowerCase()); } @Test public void gettingOcspCertificate_whenTslIsNotLoaded() throws Exception { Configuration configuration = new Configuration(Configuration.Mode.TEST); TSLCertificateSource certificateSource = new TSLCertificateSourceImpl(); configuration.setTSL(certificateSource); Container container = ContainerBuilder. aContainer(). withConfiguration(configuration). fromExistingFile("testFiles/valid-containers/valid-bdoc-tm.bdoc"). build(); Signature signature = container.getSignatures().get(0); assertNotNull(signature.getOCSPCertificate()); } private Signature getSignature(Container.DocumentType documentType) { Container container = ContainerBuilder. aContainer(documentType.name()). withConfiguration(new Configuration(Configuration.Mode.TEST)). withDataFile("testFiles/test.txt", "text/plain"). build(); Signature signature = SignatureBuilder. aSignature(container). withSignatureToken(PKCS12_SIGNER). invokeSigning(); container.addSignature(signature); return signature; } private Container createDDoc() { return ContainerBuilder. aContainer(DDOC_CONTAINER_TYPE). build(); } private void verifySignatureWithoutProductionPlaceDoesntThrow(Container container) { Signature signature = SignatureBuilder. aSignature(container). withSignatureToken(PKCS12_SIGNER). invokeSigning(); assertProductionPlaceIsNull(signature); } private void assertProductionPlaceIsNull(Signature signature) { assertNull(signature.getCity()); assertNull(signature.getCountryName()); assertNull(signature.getPostalCode()); assertNull(signature.getStateOrProvince()); } private Signature createSignatureFor(String containerType, SignatureProfile signatureProfile) throws IOException { Container container = TestDataBuilder.createContainerWithFile(testFolder, containerType); Signature signature = SignatureBuilder. aSignature(container). withSignatureToken(PKCS12_SIGNER). withSignatureProfile(signatureProfile). invokeSigning(); return signature; } }