diff options
12 files changed, 183 insertions, 23 deletions
diff --git a/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java b/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java index 84e5299..05ecac1 100644 --- a/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java +++ b/src/main/java/at/gv/egiz/moazs/config/MoaSigConfig.java @@ -90,13 +90,14 @@ public class MoaSigConfig { } @Bean - public SignatureVerifier signatureVerifier(@Value("${moa.spss.is-active}") boolean isMoaSPSSActive) { + public SignatureVerifier signatureVerifier(@Value("${moa.spss.is-active}") boolean isMoaSPSSActive, + @Value("${moa.spss.is-manifest-check-active}") boolean isManifestCheckActive) { if (isMoaSPSSActive) { log.info("Moa SPSS is active. Signatures in SOAP Messages will be verified."); - return new MoaSPSSSignatureVerifier(moaSigVerifyService(), defaultTrustProfile); + return new MoaSPSSSignatureVerifier(moaSigVerifyService(), defaultTrustProfile, isManifestCheckActive); } else { log.warn("Moa SPSS is not active. Signatures in SOAP Messages will not be verified."); - return signedXMLdocument -> true; + return signedXMLdocument -> {}; } } } diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java index 9f2b6d4..920e90d 100644 --- a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java +++ b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java @@ -75,11 +75,12 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline { status = msgClientFactory.create(msgRequest, mzsRequest.getConfig(), interceptor).send(); var signedStatus = repository.getSignedDeliveryRequestStatus(appDeliveryId).get(); - if (verifier.verify(signedStatus)) { - repository.add(status); - } else { + + try { + verifier.verify(signedStatus); + } catch (Exception ex) { throw moaZSExceptionBuilder("Signature of DeliveryRequestStatus with AppDeliveryId={} " + - "is invalid.", appDeliveryId) + " is not valid.", appDeliveryId) .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) .withMzsRequest(mzsRequest) .withTnvzResult(tnvzResult) @@ -87,6 +88,9 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline { .withMsgResult(status) .build(); } + + repository.add(status); + } catch (MoaZSException exception) { var errorStatus = generateErrorStatus(exception, appDeliveryId); repository.add(errorStatus); diff --git a/src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java b/src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java index 518cdb3..0757c5d 100644 --- a/src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java +++ b/src/main/java/at/gv/egiz/moazs/verify/MoaSPSSSignatureVerifier.java @@ -1,10 +1,15 @@ package at.gv.egiz.moazs.verify; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService; +import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.data.IXMLSignatureVerificationResponse; import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.exceptions.MOASigServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static at.gv.egiz.moazs.MoaZSException.moaZSException; +import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; +import static java.lang.String.*; + public class MoaSPSSSignatureVerifier implements SignatureVerifier { private static final Logger log = LoggerFactory.getLogger(MoaSPSSSignatureVerifier.class); @@ -13,22 +18,94 @@ public class MoaSPSSSignatureVerifier implements SignatureVerifier { private final String trustProfile; + private final boolean isManifestCheckActive; + + private static final int OK_CODE = 0; + public MoaSPSSSignatureVerifier(ISignatureVerificationService service, - String trustProfile) { + String trustProfile, boolean isManifestCheckActive) { this.service = service; this.trustProfile = trustProfile; + this.isManifestCheckActive = isManifestCheckActive; } @Override - public boolean verify(byte[] signedXMLdocument) { + public void verify(byte[] signedXMLdocument) { try { var response = service.verifyXMLSignature(signedXMLdocument, trustProfile); - return response != null; + + if (log.isDebugEnabled()) { + print(response); + } + + if (response == null) { + throw moaZSException("MOA SPSS could not find the signature. "); + } + + var builder = new StringBuilder(); + + if (response.getSignatureCheckCode() != OK_CODE) { + builder.append(format("Signature is not valid; SignatureCheckCode was %d. ", + response.getSignatureCheckCode())); + } + + if (response.getCertificateCheckCode() != OK_CODE) { + builder.append(format("Certificate chain is not valid; CertificateCheckCode was %d. ", + response.getCertificateCheckCode())); + } + + if (response.getSignatureManifestCheckCode() != OK_CODE) { + var signatureManifestErrorMsg = format("Signature Manifest is not valid; " + + "SignatureManifestCheckCode was %d. ", response.getSignatureManifestCheckCode()); + if (isManifestCheckActive) { + builder.append(signatureManifestErrorMsg); + } else { + log.warn(signatureManifestErrorMsg); + } + } + + if (response.isXmlDSIGManigest() && response.getXmlDSIGManifestCheckCode() != OK_CODE) { + var xmlDSIGManifestErrorMsg = format("XmlDSIGManifest Manifest is not valid; " + + "XmlDSIGManifest was %d. ", response.getXmlDSIGManifestCheckCode()); + if (isManifestCheckActive) { + builder.append(xmlDSIGManifestErrorMsg); + } else { + log.warn(xmlDSIGManifestErrorMsg); + } + } + + var msg = builder.toString(); + + if(msg.length() > 0) { + throw moaZSException(msg); + } + } catch (MOASigServiceException e) { - MoaSPSSSignatureVerifier.log.error("Could not verify the XML signature.", e); - return false; + throw moaZSExceptionBuilder("Could not verify the XML signature.") + .withCause(e) + .build(); + } + + } + + private void print(IXMLSignatureVerificationResponse response) { + log.debug("Response:"); + + if (response == null) { + log.debug("null"); + return; } + log.debug(" XmlDsigSubjectName: " + response.getXmlDsigSubjectName()); + log.debug(" SignatureManifestCheckCode: " + response.getSignatureManifestCheckCode()); + log.debug(" XmlDSIGManifestCheckCode: " + response.getXmlDSIGManifestCheckCode()); + log.debug(" CertificateCheckCode: " + response.getCertificateCheckCode()); + log.debug(" SignatureCheckCode: " + response.getSignatureCheckCode()); + log.debug(" SigningDateTime: " + response.getSigningDateTime()); + log.debug(" isXmlDSIGManigest: " + response.isXmlDSIGManigest()); + log.debug(" isPublicAuthority: " + response.isPublicAuthority()); + log.debug(" isQualifiedCertificate: " + response.isQualifiedCertificate()); + log.debug(" getPublicAuthorityCode: " + response.getPublicAuthorityCode()); } } diff --git a/src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java b/src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java index 01e90c8..a31c4cf 100644 --- a/src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java +++ b/src/main/java/at/gv/egiz/moazs/verify/SignatureVerifier.java @@ -4,10 +4,10 @@ package at.gv.egiz.moazs.verify; public interface SignatureVerifier { /** - * Verifies the signature of a signed XML document. + * Verifies the signature of a signed XML document. Throws a at.gv.egiz.moazs.MoaZSException exception + * if the validation fails. * @param signedXMLdocument - * @return true if the signature is valid; false if there is no signature, if the signature is invalid, - * or if an exception occured. + * @throws at.gv.egiz.moazs.MoaZSException */ - boolean verify(byte[] signedXMLdocument); + void verify(byte[] signedXMLdocument); } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 961f437..9ce1158 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -80,6 +80,8 @@ javax.net.ssl: ### moa spss config moa.spss: is-active: true + # if active, moa spss will validate manifests in xml signatures + is-manifest-check-active: false server: # path that points to MoaSPSSConfiguration file; can be: # - absolute path (unix: starts with /), or diff --git a/src/main/resources/moa-spss/certstore/toBeAdded/IAIK_test_intermediate_CA.der b/src/main/resources/moa-spss/certstore/toBeAdded/IAIK_test_intermediate_CA.der Binary files differnew file mode 100644 index 0000000..558ce15 --- /dev/null +++ b/src/main/resources/moa-spss/certstore/toBeAdded/IAIK_test_intermediate_CA.der diff --git a/src/main/resources/moa-spss/certstore/toBeAdded/msz-test-root-cert.der b/src/main/resources/moa-spss/certstore/toBeAdded/msz-test-root-cert.der Binary files differdeleted file mode 100644 index 3e136d4..0000000 --- a/src/main/resources/moa-spss/certstore/toBeAdded/msz-test-root-cert.der +++ /dev/null diff --git a/src/main/resources/moa-spss/trustProfiles/test-trustprofile/IAIK_test_intermediate_CA.der b/src/main/resources/moa-spss/trustProfiles/test-trustprofile/IAIK_test_intermediate_CA.der Binary files differnew file mode 100644 index 0000000..558ce15 --- /dev/null +++ b/src/main/resources/moa-spss/trustProfiles/test-trustprofile/IAIK_test_intermediate_CA.der diff --git a/src/main/resources/moa-spss/trustProfiles/test-trustprofile/msz-test-root-cert.der b/src/main/resources/moa-spss/trustProfiles/test-trustprofile/msz-test-root-cert.der Binary files differdeleted file mode 100644 index 3e136d4..0000000 --- a/src/main/resources/moa-spss/trustProfiles/test-trustprofile/msz-test-root-cert.der +++ /dev/null diff --git a/src/test/java/at/gv/egiz/moazs/MoaSPSSSignatureVerifierTest.java b/src/test/java/at/gv/egiz/moazs/MoaSPSSSignatureVerifierTest.java new file mode 100644 index 0000000..afa817f --- /dev/null +++ b/src/test/java/at/gv/egiz/moazs/MoaSPSSSignatureVerifierTest.java @@ -0,0 +1,49 @@ +package at.gv.egiz.moazs; + +import at.gv.egiz.eid.authhandler.modules.sigverify.moasig.api.ISignatureVerificationService; +import at.gv.egiz.moazs.verify.MoaSPSSSignatureVerifier; +import at.gv.egiz.moazs.verify.SignatureVerifier; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +@RunWith(SpringRunner.class) +@SpringBootTest + public class MoaSPSSSignatureVerifierTest { + + private final String resourcesPath = "src/test/resources/at/gv/egiz/moazs/MoaSPSSSignatureVerifierTest/"; + + @TestConfiguration + public class Config{ + + @Bean + public SignatureVerifier verifier(@Autowired ISignatureVerificationService service){ + return new MoaSPSSSignatureVerifier(service, "test-trust-profile", true); + } + + } + + @Autowired + private SignatureVerifier verifier; + + //TODO make sure that testcase does not depend on runtime because it's certificate expires in 2023-09-27. + @Test + public void acceptValidSignedDeliveryResponse() throws IOException { + + var path = resourcesPath + "valid-signed-delivery-response.xml"; + var signature = Files.readAllBytes(new File(path).toPath()); + + verifier.verify(signature); + } + +} diff --git a/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java b/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java index 768f376..cd454f2 100644 --- a/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java +++ b/src/test/java/at/gv/egiz/moazs/SameThreadDeliveryPipelineTest.java @@ -20,10 +20,12 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import java.util.List; +import static at.gv.egiz.moazs.MoaZSException.moaZSException; import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder; import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Payload; import static at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Payload.payloadBuilder; @@ -148,7 +150,8 @@ public class SameThreadDeliveryPipelineTest { @Test public void rejectInvalidSignature() { var appDeliveryId = "invalid-signature"; - setupMocks(appDeliveryId, true, List.of(), List.of("*/*"), false); + setupMocks(appDeliveryId, true, List.of(), List.of("*/*")); + doThrow(moaZSException("Signature Invalid!")).when(verifier).verify(any()); pipeline.processRequest(appDeliveryId); var actualCode = repository.getDeliveryRequestStatus(appDeliveryId).get() @@ -160,11 +163,6 @@ public class SameThreadDeliveryPipelineTest { private DeliveryRequestStatusType setupMocks(String appDeliveryId, boolean tnvzRequest, List<String> attachedTypes, List<String> acceptedTypes) { - return setupMocks(appDeliveryId, tnvzRequest, attachedTypes, acceptedTypes, true); - } - - private DeliveryRequestStatusType setupMocks(String appDeliveryId, boolean tnvzRequest, - List<String> attachedTypes, List<String> acceptedTypes, boolean isSignedStatusValid) { var mzsRequest = setupMzsRequest(appDeliveryId, tnvzRequest, attachedTypes); var msgRequest = setupMsgRequest(appDeliveryId); @@ -178,7 +176,6 @@ public class SameThreadDeliveryPipelineTest { when(converter.convert(eq(mzsRequest), any())).thenReturn(msgRequest); when(msgClientFactory.create(msgRequest, mzsRequest.getConfig(), interceptor)).thenReturn(msgClient); when(msgClient.send()).thenReturn(status); - when(verifier.verify(signedStatus)).thenReturn(isSignedStatusValid); return status; diff --git a/src/test/resources/at/gv/egiz/moazs/MoaSPSSSignatureVerifierTest/valid-signed-delivery-response.xml b/src/test/resources/at/gv/egiz/moazs/MoaSPSSSignatureVerifierTest/valid-signed-delivery-response.xml new file mode 100644 index 0000000..59a90cf --- /dev/null +++ b/src/test/resources/at/gv/egiz/moazs/MoaSPSSSignatureVerifierTest/valid-signed-delivery-response.xml @@ -0,0 +1,30 @@ +<DeliveryResponse xmlns="http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#" xmlns:ns2="http://reference.e-government.gv.at/namespace/persondata/phase2/20181206#" xmlns:ns3="http://www.w3.org/2000/09/xmldsig#"><PartialSuccess><DeliverySystem>https://testzustellsystem.egiz.gv.at</DeliverySystem><ZSDeliveryID>zs-valid-delivery-request-id</ZSDeliveryID><AppDeliveryID>valid-delivery-request-id</AppDeliveryID><GZ>12345</GZ></PartialSuccess><dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Id="signature-1-1"><dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><dsig:Reference Id="reference-1-1" URI=""><dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><dsig:DigestValue>ejvUI0yh/IIyauFe8x5ZonD/i5oznl8vFyS3oLNivzA=</dsig:DigestValue></dsig:Reference></dsig:SignedInfo><dsig:SignatureValue>hmVZrLkMDbXaRLYQKOaV3OtK13TQgMu3csKyw9M4zWqNyva1yxnYkzoX3dKDOdc9 +O56yQJsjoA3Cuw7pXlGO7jSfVM77dTXbWSDaF95O9Vdsrmr7R6Uki0jA9SmgQLXg +hZAUG8JpsHcBn8M0L2BXADKjSn0LuMDL2L7dmU3EM7eRy+OvFwDrXDw1fhjQO6L2 +KoflAWLgUerDhJSpzr0+YfmkrjzitLUA7oIg8ieOnfGyql31ECmDJEqgnL78hyPZ +KaNZImDf3EWFs8je6mt+os1TwsyXYwz+GGbjoDR8lGTS9xVqnXdrgP8Jyv6p9FEu +0IYgSY2FlbI3skPZC8ZVXg==</dsig:SignatureValue><dsig:KeyInfo><dsig:X509Data><dsig:X509Certificate>MIIEqzCCBBSgAwIBAgIHANux81oNezANBgkqhkiG9w0BAQUFADBAMSIwIAYDVQQD +ExlJQUlLIFRlc3QgSW50ZXJtZWRpYXRlIENBMQ0wCwYDVQQKEwRJQUlLMQswCQYD +VQQGEwJBVDAeFw0xMzA5MjcwNTMzMzdaFw0yMzA5MjcwNTMzMzdaMIHkMQswCQYD +VQQGEwJBVDENMAsGA1UEBxMER3JhejEmMCQGA1UEChMdR3JheiBVbml2ZXJzaXR5 +IG9mIFRlY2hub2xvZ3kxSDBGBgNVBAsTP0luc3RpdHV0ZSBmb3IgQXBwbGllZCBJ +bmZvcm1hdGlvbiBQcm9jZXNzaW5nIGFuZCBDb21tdW5pY2F0aW9uczEUMBIGA1UE +BBMLTU9BLVNTIFRlc3QxGDAWBgNVBCoTD0VHSVogVGVzdHBvcnRhbDEkMCIGA1UE +AxMbRUdJWiBUZXN0cG9ydGFsIE1PQS1TUyBUZXN0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAuDjOyf+mY+oQL2FQzzuaiC8C23vVKbq/n2Zi7BqSibZH +mtqMJfmj4pT+hWSNHvVvWsaxFcx4KeNqdCMzwnw1r4P3Sf+2o5uFku5KHEMLMokR +yYQG9VqY/KkB94ye7Pv6zT8gvKqxGFg96UamECep4swPaSZrA8AOER5WAtyGDzKI +Tz+a5zfFaTXDoba7f98PCWR96yKiFjVOhzp38WVz4VJgz+b8ZSY7Xsv5Kn7DXjOL +STX4MevFLki3rFPup3+4vGToaMBW3PEj67HXBdqR855Le6+E6rVxORqsXqlVwhsI +6nuS0CO2LWYmBNR1IB0mXteeYH/HfxvuZc+7yDjdPQIDAQABo4IBhDCCAYAwDgYD +VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEmcH6VY4BG1EAGB +TLoNR9vH/g6yMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9jcmxzL0lBSUtUZXN0X0ludGVybWVkaWF0ZUNBLmNybDCBqgYI +KwYBBQUHAQEEgZ0wgZowSgYIKwYBBQUHMAGGPmh0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9PQ1NQP2NhPUlBSUtUZXN0X0ludGVybWVkaWF0ZUNBMEwGCCsG +AQUFBzAChkBodHRwOi8vY2EuaWFpay50dWdyYXouYXQvY2Fwc28vY2VydHMvSUFJ +S1Rlc3RfSW50ZXJtZWRpYXRlQ0EuY2VyMCEGA1UdEQQaMBiBFnRob21hcy5sZW56 +QGVnaXouZ3YuYXQwHwYDVR0jBBgwFoAUaKJeEdreL4BrRES/jfplNoEkp28wDQYJ +KoZIhvcNAQEFBQADgYEAlFGjUxXLs7SAT8NtXSrv2WrjlklaRnHTFHLQwyVo8JWb +gvRkHHDUv2o8ofXUY2R2WJ38dxeDoccgbXrJb/Qhi8IY7YhCwv/TuIZDisyAqo8W +ORKSip/6HWlGCSR/Vgoet1GtCmF0FoUxFUIGSAuQ2yyt4fIzt5GJrU1X5ujjI1w=</dsig:X509Certificate></dsig:X509Data></dsig:KeyInfo></dsig:Signature></DeliveryResponse> |