diff --git a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIKeystoreService.java b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIKeystoreService.java index a0650df4ec237a2ee5e2752d390e6628aaf58505..14545fe376da374249e6691fe13d0a80ce416f8f 100644 --- a/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIKeystoreService.java +++ b/smp-server-library/src/main/java/eu/europa/ec/edelivery/smp/services/ui/UIKeystoreService.java @@ -15,6 +15,7 @@ import org.springframework.stereotype.Service; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import java.io.*; +import java.nio.file.Files; import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -137,7 +138,7 @@ public class UIKeystoreService extends BasicKeystoreService { KeyStore keyStore; - try (InputStream keystoreInputStream = new FileInputStream(keyStoreFile)) { + try (InputStream keystoreInputStream = Files.newInputStream(keyStoreFile.toPath())) { String type = StringUtils.defaultIfEmpty(configurationService.getKeystoreType(), "JKS"); LOG.info("Load keystore [{}] with type [{}].", keyStoreFile, type); keyStore = KeyStore.getInstance(type); @@ -193,7 +194,7 @@ public class UIKeystoreService extends BasicKeystoreService { } if (keystoreKeys.isEmpty()) { - throw new SMPRuntimeException(ErrorCode.CONFIGURATION_ERROR, "Could not retrieve key: " + keyAlias + " from empty keystore!" + configurationService.getKeystoreFile()); + throw new SMPRuntimeException(ErrorCode.CONFIGURATION_ERROR, "Could not retrieve key: [" + keyAlias + "] from empty keystore: [" + configurationService.getKeystoreFile() +"]!"); } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataSignerTest.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataSignerTest.java index 260aa98bc10c138731b7142a707a1e1ed90bc6e8..f5d5517d6bb3cdc7a975649e52dea8b5a70c8168 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataSignerTest.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/services/ServiceMetadataSignerTest.java @@ -13,14 +13,20 @@ package eu.europa.ec.edelivery.smp.services; +import eu.europa.ec.edelivery.smp.data.dao.AbstractJunit5BaseDao; import eu.europa.ec.edelivery.smp.services.spi.SmpXmlSignatureService; import eu.europa.ec.edelivery.smp.services.ui.UIKeystoreService; -import org.junit.Before; -import org.junit.Ignore; +import eu.europa.ec.edelivery.smp.testutil.SignatureUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.util.ReflectionTestUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import java.io.File; import java.nio.file.Path; @@ -28,11 +34,15 @@ import java.nio.file.Paths; /** - * Created by rodrfla on 20/02/2017. + * metadata tests signatures + * + * @author Flavio Santos + * @author Joze Rihtarsic + * @since 3.0 + */ -@Ignore @ContextConfiguration(classes = { SmpXmlSignatureService.class}) -public class ServiceMetadataSignerTest extends AbstractServiceIntegrationTest{ +public class ServiceMetadataSignerTest extends AbstractJunit5BaseDao{ Path resourceDirectory = Paths.get("src", "test", "resources", "keystores"); @@ -44,24 +54,24 @@ public class ServiceMetadataSignerTest extends AbstractServiceIntegrationTest{ @Autowired private SmpXmlSignatureService signer; - @Before + @BeforeEach public void setup(){ configurationService = Mockito.spy(configurationService); ReflectionTestUtils.setField(uiKeystoreService,"configurationService",configurationService); ReflectionTestUtils.setField(signer,"uiKeystoreService",uiKeystoreService); // set keystore properties - File keystoreFile = new File(resourceDirectory.toFile(), "smp-keystore.jks"); + File keystoreFile = new File(resourceDirectory.toAbsolutePath().toFile(), "smp-keystore-all-keys.p12"); Mockito.doReturn( keystoreFile).when(configurationService).getKeystoreFile(); Mockito.doReturn( resourceDirectory.toFile()).when(configurationService).getSecurityFolder(); Mockito.doReturn("test123").when(configurationService).getKeystoreCredentialToken(); + Mockito.doReturn("PKCS12").when(configurationService).getKeystoreType(); uiKeystoreService.refreshData(); } -/* - private Document loadAndSignDocumentForDefault() throws Exception { - Document documentToSign = loadDocument("/input/SignedServiceMetadata_withoutSignature.xml"); - signer.sign(documentToSign, null, ALGO_ID_SIGNATURE_RSA_SHA256, SHA256); + private Document loadAndSignDocumentForDefault(String alias) throws Exception { + Document documentToSign = SignatureUtil.loadDocument("/input/SignedServiceMetadata_withoutSignature.xml"); + signer.sign(documentToSign, alias, null, null); return documentToSign; } @@ -70,43 +80,25 @@ public class ServiceMetadataSignerTest extends AbstractServiceIntegrationTest{ SignatureUtil.validateSignature(smpSigPointer); } - private Element loadAndSignDocumentForAdmin(String filePath) throws Exception { - Document response = loadDocument(filePath); - Element smNode = SignatureUtil.findFirstElementByName(response, "ServiceMetadata"); - Document docUnwrapped = SignatureUtil.buildDocWithGivenRoot(smNode); - Element adminSignature = SignatureUtil.findServiceInfoSig(docUnwrapped); - + Document response = SignatureUtil.loadDocument(filePath); + Element adminSignature = SignatureUtil.findServiceInfoSig(response); return adminSignature; } - @Test - public void testDefaultSignatureOk() throws Exception { - Document document = loadAndSignDocumentForDefault(); + @ParameterizedTest + @ValueSource(strings = {"sample_key", + "smp_ecdsa_nist-b409", + "smp_eddsa_25519", + "smp_eddsa_448"}) + public void testSignatureAndDefaultAlgorithmeDefinitionOk(String alias) throws Exception { + Document document = loadAndSignDocumentForDefault(alias); validateSignatureForDefault(document); } - @Test(expected = Exception.class) - public void testDefaultSignatureNotOk() throws Exception { - Document document = loadAndSignDocumentForDefault(); - String documentStr = SignatureUtil.marshall(document); - documentStr = documentStr.replace("<Process>", "<Process><DummyElement></DummyElement>"); - validateSignatureForDefault(SignatureUtil.parseDocument(documentStr)); - } - @Test public void testAdminSignatureOk() throws Exception { Element adminSignature = loadAndSignDocumentForAdmin("/expected_output/PUT_ServiceMetadata_request.xml"); - SignatureUtil.validateSignature(adminSignature); } - - @Test(expected = Exception.class) - public void testAdminSignatureNotOk() throws Exception { - Element adminSignature = loadAndSignDocumentForAdmin("/expected_output/PUT_ServiceMetadata_request_not_valid.xml"); - - SignatureUtil.validateSignature(adminSignature); - } -*/ - } diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/SignatureUtil.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/SignatureUtil.java index 7f86bbebda334b039b3e6b0c2e984705c3edd26a..e33a7e13fe3490d39651b2de39a88b195daa6765 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/SignatureUtil.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/SignatureUtil.java @@ -29,6 +29,8 @@ import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; import javax.xml.crypto.dsig.keyinfo.X509Data; import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; import javax.xml.crypto.dsig.spec.TransformParameterSpec; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; @@ -61,9 +63,16 @@ public class SignatureUtil { private static KeyStore.PrivateKeyEntry privateKeyEntry; private static KeyInfo keyInfo; + private static XMLSignatureFactory getDomSigFactory() { + // According to Javadoc, only static methods of this factory are thread-safe + // We cannot share and re-use the same instance in every place + // set apache santuario xmlsec signature factory + return XMLSignatureFactory.getInstance("DOM", new org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI()); + } + private static void setupSigner(String keystoreResPath, String keystorePass, String keyPairAlias, String keyPairPass) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, UnrecoverableEntryException, IOException { // Initialize all stuff needed for signing: Load keys from keystore and prepare signature factory - sigFactory = XMLSignatureFactory.getInstance("DOM"); + sigFactory = getDomSigFactory(); KeyStore ks = KeyStore.getInstance("JKS"); InputStream keystoreStream = SignatureUtil.class.getResourceAsStream(keystoreResPath); ks.load(keystoreStream, keystorePass.toCharArray()); @@ -102,7 +111,7 @@ public class SignatureUtil { } public static void validateSignature(Element sigPointer) throws Exception { - XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); + XMLSignatureFactory fac = getDomSigFactory(); // Create a DOMValidateContext and specify a KeySelector and document context. DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), sigPointer); @@ -164,7 +173,6 @@ public class SignatureUtil { } - public static Element findServiceInfoSig(Document doc) throws ParserConfigurationException, SAXException, IOException { Element extension = findExtensionInServiceInformation(doc); return findSignatureByParentNode(extension); @@ -180,7 +188,6 @@ public class SignatureUtil { } - public static Element findExtensionInServiceInformation(Document doc) throws ParserConfigurationException, SAXException, IOException { Element serviceInformation = findFirstElementByName(doc, "ServiceInformation"); @@ -198,6 +205,19 @@ public class SignatureUtil { return extension; } + public static Document loadDocument(String docResourcePath) throws ParserConfigurationException, SAXException, IOException { + InputStream inputStreamm = SignatureUtil.class.getResourceAsStream(docResourcePath); + return getDocumentBuilder().parse(inputStreamm); + } + + + public static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + return dbf.newDocumentBuilder(); + } + + public static Element findFirstElementByName(Document doc, String elementName) { NodeList elements = doc.getElementsByTagNameNS(OASIS_NS, elementName); return (Element) elements.item(0); diff --git a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509KeySelector.java b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509KeySelector.java index b6caa945c638e7172bae82e87f831189b30cc869..0357d1a9dfb4fb7e9052fa36c686ed0c770b48db 100644 --- a/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509KeySelector.java +++ b/smp-server-library/src/test/java/eu/europa/ec/edelivery/smp/testutil/X509KeySelector.java @@ -14,14 +14,16 @@ package eu.europa.ec.edelivery.smp.testutil; import javax.xml.crypto.*; -import javax.xml.crypto.dsig.SignatureMethod; import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.crypto.dsig.keyinfo.X509Data; -import java.security.Key; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.Iterator; +/** + * This test class is used to extract the public key from an X509 certificate. + * It is used in the test cases to verify the signature of the SML response. + */ public class X509KeySelector extends KeySelector { private X509Certificate certificate; @@ -50,26 +52,12 @@ public class X509KeySelector extends KeySelector { final PublicKey key = this.certificate.getPublicKey(); // Make sure the algorithm is compatible // with the method. - if (algEquals(method.getAlgorithm(), key.getAlgorithm())) { - return new KeySelectorResult() { - public Key getKey() { - return key; - } - }; - } + return () -> key; } } throw new KeySelectorException("No key found!"); } - static boolean algEquals(String algorithmURI, String algorithmName) { - return (algorithmName.equalsIgnoreCase("DSA") && - algorithmURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) - || (algorithmName.equalsIgnoreCase("RSA") && - algorithmURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) - || (algorithmName.equalsIgnoreCase("RSA") - && algorithmURI.equalsIgnoreCase("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")); - } public X509Certificate getCertificate() { return this.certificate; diff --git a/smp-server-library/src/test/resources/keystores/smp-keystore-all-keys.p12 b/smp-server-library/src/test/resources/keystores/smp-keystore-all-keys.p12 new file mode 100644 index 0000000000000000000000000000000000000000..b98490ab6f55a61121fd59f5911cbb32556aadd2 Binary files /dev/null and b/smp-server-library/src/test/resources/keystores/smp-keystore-all-keys.p12 differ diff --git a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SignatureValidatorTest.java b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SignatureValidatorTest.java index ad3fdeedcbf409d33afd08a4c89057c7e2d986c4..e3df551ad8247b26d8fdac995759ee0dd0d2f805 100644 --- a/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SignatureValidatorTest.java +++ b/smp-webapp/src/test/java/eu/europa/ec/edelivery/smp/server/security/SignatureValidatorTest.java @@ -83,7 +83,6 @@ public class SignatureValidatorTest { @Autowired private WebApplicationContext webAppContext; - private MockMvc mvc; @Before