From a84dff7c31155b433765e209c72ce5749a32390d Mon Sep 17 00:00:00 2001 From: kholtermann Date: Wed, 27 Dec 2023 12:51:08 +0100 Subject: [PATCH] Release eumw-3.2.0 --- .hgtags | 5 +- configuration-migration/pom.xml | 26 +- .../migration/models/eidas/ConfigHolder.java | 5 +- .../models/poseidas/CoreConfigurationDto.java | 6 +- .../models/poseidas/PoseidasConfigurator.java | 2 +- .../xjb/generated-source-settings.xjb | 4 +- .../src/test/resources/keys/demo_sig.cer | 40 +- .../src/test/resources/keys/middleware.p12 | Bin 2439 -> 4124 bytes .../src/test/resources/metadata/Metadata.xml | 16 +- databasemigration/pom.xml | 2 +- distribution/pom.xml | 4 +- doc/source/chapter/Changelog.rst | 14 +- doc/source/chapter/Configuration.rst | 59 +- doc/source/chapter/DemoApplication.rst | 19 +- doc/source/chapter/Operating.rst | 8 +- doc/source/chapter/Requirements.rst | 4 +- doc/source/chapter/application.properties | 4 +- .../eIDAS_Middleware_configuration_prod.xml | 8 +- .../eIDAS_Middleware_configuration_test.xml | 4 +- doc/source/conf.py | 4 +- doc/source/images/Certs_and_Interfaces.png | Bin 110125 -> 117835 bytes .../images/certs-and-interfaces.graphml | 3500 +++++++++-------- eidas-base-container/pom.xml | 2 +- .../src/main/docker/Dockerfile | 2 +- eidas-common/pom.xml | 6 +- .../eumw/eidascommon/ContextPaths.java | 2 +- .../eumw/eidascommon/CryptoAlgUtil.java | 62 +- .../eumw/eidascommon/ErrorCode.java | 55 +- .../eumw/eidascommon/HttpRedirectUtils.java | 2 +- .../de/governikus/eumw/eidascommon/Utils.java | 158 +- eidas-demo/README.txt | 9 - eidas-demo/pom.xml | 2 +- .../governikus/eumw/eidasdemo/Metadata.java | 4 +- .../eumw/eidasdemo/NewReceiverServlet.java | 6 +- .../eumw/eidasdemo/NewRequesterServlet.java | 4 +- .../eumw/eidasdemo/SamlExampleHelper.java | 11 +- eidas-middleware/pom.xml | 7 +- .../eidasmiddleware/MetadataServiceImpl.java | 11 +- .../eumw/eidasmiddleware/StartUpListener.java | 4 +- .../controller/RequestReceiver.java | 6 +- .../controller/ResponseSender.java | 4 +- .../eidasmiddleware/controller/TcToken.java | 2 +- .../entities/RequestSession.java | 12 +- .../handler/RequestHandler.java | 45 +- .../handler/ResponseHandler.java | 26 +- .../projectconfig/PortCreator.java | 38 +- .../projectconfig/PortFilter.java | 8 +- .../resources/i18n/messages_de.properties | 20 +- .../resources/i18n/messages_en.properties | 16 +- ...weisapp2-xl.png => logo-ausweisapp-xl.png} | Bin ...go-ausweisapp2.png => logo-ausweisapp.png} | Bin .../resources/static/img/screenshot-aa2.png | Bin 61040 -> 0 bytes .../main/resources/templates/middleware.html | 16 +- .../eumw/eidasmiddleware/EidasRoundTrip.java | 23 +- .../MetadataServiceImplTest.java | 2 +- .../eumw/eidasmiddleware/Metadatatest.java | 2 +- .../eidasmiddleware/RequestSessionTest.java | 16 +- .../handler/RequestHandlerMatrixTest.java | 2 +- .../handler/RequestHandlerTest.java | 92 +- .../handler/RequestHelper.java | 107 + .../handler/ResponseHandlerTest.java | 18 +- .../repositories/RequestSessionTestSetup.java | 2 +- .../test/resources/EidasSignerTest_x509.cer | Bin 928 -> 1688 bytes .../bos-test-tctoken.saml-encr.p12 | Bin 4156 -> 4218 bytes .../bos-test-tctoken.saml-sign.p12 | Bin 4156 -> 4218 bytes .../middleware-crypt.jks | Bin 2058 -> 3725 bytes .../middleware-sign.p12 | Bin 2425 -> 4158 bytes .../src/test/resources/eidassignertest.p12 | Bin 2656 -> 4156 bytes eidas-starterkit/pom.xml | 32 +- .../eumw/eidasstarterkit/EidasEncrypter.java | 136 +- .../eumw/eidasstarterkit/EidasLoaEnum.java | 2 +- .../eidasstarterkit/EidasMetadataNode.java | 49 +- .../eidasstarterkit/EidasMetadataService.java | 65 +- .../EidasNaturalPersonAttributes.java | 18 +- .../eumw/eidasstarterkit/EidasRequest.java | 16 +- .../eumw/eidasstarterkit/EidasResponse.java | 104 +- .../eumw/eidasstarterkit/EidasSaml.java | 102 +- .../eumw/eidasstarterkit/EidasSigner.java | 41 +- .../eumw/eidasstarterkit/SPTypeHelper.java | 8 +- .../eidasstarterkit/XMLSignatureHandler.java | 2 +- .../attributes/NationalityType.java | 4 +- .../AbstractNonLatinScriptAttribute.java | 2 +- .../CurrentAddressAttribute.java | 4 +- .../GenderAttribute.java | 6 +- .../NationalityAttribute.java | 2 +- .../PersonIdentifierAttribute.java | 4 +- .../PlaceOfBirthAttribute.java | 4 +- .../EidasMetadataServiceTest.java | 4 +- .../eidasstarterkit/EidasRequestTest.java | 12 +- .../eumw/eidasstarterkit/EidasSignerTest.java | 51 + .../eumw/eidasstarterkit/TestEidasSaml.java | 7 +- .../resources/EidasSignerTest_x509-old.cer | Bin 0 -> 928 bytes .../test/resources/EidasSignerTest_x509.cer | Bin 928 -> 1688 bytes .../resources/brainpoolP512r1-explicit.p12 | Bin 0 -> 2338 bytes .../src/test/resources/eidassignertest.jks | Bin 2289 -> 0 bytes .../src/test/resources/eidassignertest.p12 | Bin 2656 -> 4156 bytes .../src/test/resources/rsa-2048.p12 | Bin 0 -> 2524 bytes .../src/test/resources/secp224r1.p12 | Bin 0 -> 1115 bytes java-opensaml.patch | 1740 ++++---- pom.xml | 216 +- poseidas/pom.xml | 36 +- .../eid/RequestingServiceProvider.java | 2 +- .../eumw/poseidas/POSeIDASSecurityConfig.java | 100 +- .../asn1/npa/si/DomainParameterInfo.java | 15 +- .../npa/si/GeneralDomainParameterInfo.java | 31 - .../npa/si/StandardDomainParameterInfo.java | 54 - .../cardbase/constants/OIDConstants.java | 15 + .../cardbase/crypto/HashConstants.java | 2 +- .../poseidas/cardbase/crypto/ec/ECUtil.java | 35 +- .../cardbase/crypto/key/KeyHandler.java | 10 +- .../cardbase/crypto/key/KeyHandlerEC.java | 6 +- .../poseidas/cardbase/npa/InfoSelector.java | 24 +- .../poseidas/cardserver/CertificateUtil.java | 2 +- .../certrequest/CertificateRequest.java | 99 +- .../certrequest/CvcRequestGenerator.java | 3 +- .../cardserver/eac/protocol/EACServer.java | 16 +- .../eumw/poseidas/config/CVCController.java | 34 +- .../eumw/poseidas/config/DvcaController.java | 2 +- .../eumw/poseidas/config/EidController.java | 2 +- .../eumw/poseidas/config/EidasController.java | 97 +- .../ImportExportConfigurationController.java | 2 +- .../config/KeymanagementController.java | 2 +- .../poseidas/config/MetadataController.java | 193 +- .../poseidas/config/OverviewController.java | 2 +- .../config/ServiceProviderController.java | 3 +- .../eumw/poseidas/config/TimerController.java | 2 +- .../config/model/CertificateUploadModel.java | 2 +- .../CreateCertificateFromKeystoreModel.java | 4 +- .../model/CreateKeypairFromKeystoreModel.java | 4 +- .../config/model/KeystoreUploadModel.java | 4 +- .../MetadataVerificationCertificateModel.java | 2 +- .../config/model/ServiceProviderDetails.java | 11 +- .../config/model/forms/CVCRequestModel.java | 14 +- .../config/model/forms/DvcaConfigModel.java | 2 +- .../config/model/forms/EidConfigModel.java | 2 +- .../config/model/forms/EidasConfigModel.java | 5 +- .../forms/ServiceProviderConfigModel.java | 12 +- .../config/model/forms/TimerConfigModel.java | 4 +- .../validation/CertificateNameExists.java | 4 +- .../CertificateNameExistsValidator.java | 4 +- .../validation/DvcaConfigNameExists.java | 4 +- .../DvcaConfigNameExistsValidator.java | 4 +- .../config/validation/KeyPairNameExists.java | 4 +- .../KeyPairNameExistsValidator.java | 4 +- .../validation/ServiceProviderNameExists.java | 4 +- .../ServiceProviderNameExistsValidator.java | 4 +- .../ecardcore/utilities/ECardCoreUtil.java | 2 +- .../eidserver/convenience/EIDSequence.java | 7 +- .../eidserver/eac/EACSignedDataChecker.java | 13 +- .../eidserver/eac/EACSignedDataParser.java | 2 +- .../model/signeddata/AbstractASN1List.java | 4 +- .../authentication/paos/PaosReceiver.java | 8 +- .../paosservlet/authentication/paos/Util.java | 14 +- .../paos/handler/AbstractPaosHandler.java | 12 +- .../paos/handler/DefaultPaosHandler.java | 8 +- .../paos/handler/PaosHandlerFactory.java | 4 +- .../poseidas/server/common/CSPFilter.java | 14 +- .../idprovider/config/Configuration.java | 8 +- .../config/ConfigurationService.java | 37 +- .../server/idprovider/config/CvcTlsCheck.java | 2 +- .../idprovider/core/RequestIdStore.java | 4 +- .../idprovider/core/SessionInStore.java | 8 +- .../idprovider/core/SessionInStorePK.java | 2 +- .../idprovider/core/SessionStoreAOBean.java | 8 +- .../poseidas/server/monitoring/SNMPAgent.java | 2 +- .../server/monitoring/SNMPTrapSender.java | 4 +- .../poseidas/server/pki/BlackListEntry.java | 6 +- .../poseidas/server/pki/BlackListEntryPK.java | 2 +- .../server/pki/CVCRequestHandler.java | 65 +- .../poseidas/server/pki/CVCUpdateLock.java | 4 +- .../eumw/poseidas/server/pki/CertInChain.java | 10 +- .../poseidas/server/pki/CertInChainPK.java | 2 +- .../poseidas/server/pki/ChangeKeyLock.java | 6 +- .../server/pki/CmsSignatureChecker.java | 69 + .../poseidas/server/pki/InfoMapBuilder.java | 2 +- .../eumw/poseidas/server/pki/KeyArchive.java | 6 +- .../server/pki/PendingCertificateRequest.java | 16 +- .../server/pki/PermissionDataHandling.java | 3 +- .../server/pki/RequestSignerCertificate.java | 6 +- .../pki/ServiceProviderStatusService.java | 47 +- .../server/pki/TerminalPermission.java | 24 +- .../server/pki/TerminalPermissionAOBean.java | 10 +- .../DvcaCertDescriptionService.java | 2 +- .../caserviceaccess/PKIServiceConnector.java | 21 +- .../caserviceaccess/PassiveAuthService.java | 2 +- .../caserviceaccess/RestrictedIdService.java | 2 +- .../pki/caserviceaccess/TermAuthService.java | 2 +- .../poseidas/server/timer/BlackListTimer.java | 4 +- .../server/timer/CrlRenewalTimer.java | 4 +- .../server/timer/CvcRenewalTimer.java | 4 +- .../server/timer/GlobalListTimer.java | 4 +- .../timer/RequestSignerCvcRenewTimer.java | 4 +- .../wsdl/CA-Services/passiveAuth.dv.jxb | 6 +- .../wsdl/CA-Services/passiveAuth.dv.wsb | 2 +- .../wsdl/CA-Services/restrictedId.dv.jxb | 6 +- .../wsdl/CA-Services/restrictedId.dv.wsb | 2 +- .../META-INF/wsdl/CA-Services/termAuth.dv.jxb | 6 +- .../META-INF/wsdl/CA-Services/termAuth.dv.wsb | 2 +- .../resources/templates/fragments/form.html | 17 +- .../resources/templates/pages/details.html | 9 +- .../templates/pages/eidasConfiguration.html | 9 +- .../keymanagement/createFromKeystore.html | 4 +- .../templates/pages/keymanagement/index.html | 4 +- .../templates/pages/metadata/index.html | 4 +- .../serviceProviderConfigurationForm.html | 8 +- poseidas/src/main/xjb/serializable.xjb | 6 +- .../cardbase/npa/InfoSelectorTest.java | 22 + .../poseidas/config/CVCControllerTest.java | 12 +- .../poseidas/config/DvcaControllerTest.java | 10 +- .../poseidas/config/EidControllerTest.java | 2 +- .../poseidas/config/EidasControllerTest.java | 179 +- ...portExportConfigurationControllerTest.java | 2 +- .../config/KeymanagementControllerTest.java | 8 +- .../config/MetadataControllerTest.java | 542 ++- .../config/OverviewControllerTest.java | 2 +- .../config/ServiceProviderControllerTest.java | 4 +- .../config/ServiceProviderTestBase.java | 10 +- .../config/base/WebAdminTestBase.java | 2 +- .../eac/EACSignedDataCheckerTest.java | 83 + .../config/ConfigurationServiceTest.java | 201 +- .../server/monitoring/SNMPAgentTest.java | 4 +- .../pki/TerminalPermissionAOBeanTest.java | 2 +- .../src/test/resources/TEST_csca_germany.cer | 26 +- .../brainpoolP512r1-explicit.p12 | Bin 0 -> 2338 bytes .../test/resources/configuration/demo_epa.xml | 68 - .../resources/configuration/demo_epa_20.xml | 46 - .../configuration/demo_epa_invalid.xml | 46 - .../test/resources/configuration/keystore.jks | Bin 2045 -> 3713 bytes .../test/resources/configuration/keystore.p12 | Bin 2425 -> 4158 bytes .../resources/configuration/metadata-9443.xml | 19 + .../metadata-9444-explicit-crypt.xml | 1 + .../metadata-9444-explicit-sign.xml | 1 + .../metadata-9444-shortcrypt-ec.xml | 1 + .../metadata-9444-shortcrypt-rsa.xml | 1 + .../metadata-9444-shortsign-ec.xml | 1 + .../metadata-9444-shortsign-rsa.xml | 1 + .../resources/configuration/metadata-9444.xml | 19 + .../configuration/metadata-9445-invalid.xml | 19 + .../configuration/metadata-signer.cer | 11 + .../test/resources/configuration/rsa-2048.p12 | Bin 0 -> 2524 bytes .../resources/configuration/secp224r1.p12 | Bin 0 -> 1115 bytes .../test/resources/configuration/sigCert.crt | 20 - .../keys/bos-test-tctoken.saml-sign.p12 | Bin 0 -> 4156 bytes .../resources/keys}/bos-test.saml-sign.p12 | Bin .../test/resources/keys/ec-explicit-curve.cer | 30 + .../src/test/resources/keys/ec_saml_224.cer | Bin 0 -> 299 bytes .../src/test/resources/keys/ec_saml_256.cer | Bin 0 -> 316 bytes .../src/test/resources/keys/ec_saml_384.cer | Bin 0 -> 377 bytes .../src/test/resources/keys/ec_saml_521.cer | Bin 0 -> 453 bytes poseidas/src/test/resources/keys/ecc2.p12 | Bin 0 -> 1159 bytes .../src/test/resources/keys/rsa_saml_2048.cer | Bin 0 -> 710 bytes .../src/test/resources/keys/rsa_saml_3072.cer | Bin 0 -> 966 bytes .../src/test/resources/keys/rsa_saml_4096.cer | Bin 0 -> 1222 bytes utils/pom.xml | 8 +- .../governikus/eumw/utils/xml/XmlHelper.java | 10 +- 255 files changed, 5959 insertions(+), 4085 deletions(-) rename eidas-middleware/src/main/resources/static/img/{logo-ausweisapp2-xl.png => logo-ausweisapp-xl.png} (100%) rename eidas-middleware/src/main/resources/static/img/{logo-ausweisapp2.png => logo-ausweisapp.png} (100%) delete mode 100644 eidas-middleware/src/main/resources/static/img/screenshot-aa2.png create mode 100644 eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHelper.java create mode 100644 eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasSignerTest.java create mode 100644 eidas-starterkit/src/test/resources/EidasSignerTest_x509-old.cer create mode 100644 eidas-starterkit/src/test/resources/brainpoolP512r1-explicit.p12 delete mode 100644 eidas-starterkit/src/test/resources/eidassignertest.jks create mode 100644 eidas-starterkit/src/test/resources/rsa-2048.p12 create mode 100644 eidas-starterkit/src/test/resources/secp224r1.p12 delete mode 100644 poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/GeneralDomainParameterInfo.java delete mode 100644 poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/StandardDomainParameterInfo.java create mode 100644 poseidas/src/test/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataCheckerTest.java create mode 100644 poseidas/src/test/resources/configuration/brainpoolP512r1-explicit.p12 delete mode 100644 poseidas/src/test/resources/configuration/demo_epa.xml delete mode 100644 poseidas/src/test/resources/configuration/demo_epa_20.xml delete mode 100644 poseidas/src/test/resources/configuration/demo_epa_invalid.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9443.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9444-explicit-crypt.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9444-explicit-sign.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-ec.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-rsa.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9444-shortsign-ec.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9444-shortsign-rsa.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9444.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-9445-invalid.xml create mode 100644 poseidas/src/test/resources/configuration/metadata-signer.cer create mode 100644 poseidas/src/test/resources/configuration/rsa-2048.p12 create mode 100644 poseidas/src/test/resources/configuration/secp224r1.p12 delete mode 100644 poseidas/src/test/resources/configuration/sigCert.crt create mode 100644 poseidas/src/test/resources/keys/bos-test-tctoken.saml-sign.p12 rename {eidas-middleware/src/test/resources/de/governikus/eumw/eidasmiddleware => poseidas/src/test/resources/keys}/bos-test.saml-sign.p12 (100%) create mode 100644 poseidas/src/test/resources/keys/ec-explicit-curve.cer create mode 100644 poseidas/src/test/resources/keys/ec_saml_224.cer create mode 100644 poseidas/src/test/resources/keys/ec_saml_256.cer create mode 100644 poseidas/src/test/resources/keys/ec_saml_384.cer create mode 100644 poseidas/src/test/resources/keys/ec_saml_521.cer create mode 100644 poseidas/src/test/resources/keys/ecc2.p12 create mode 100644 poseidas/src/test/resources/keys/rsa_saml_2048.cer create mode 100644 poseidas/src/test/resources/keys/rsa_saml_3072.cer create mode 100644 poseidas/src/test/resources/keys/rsa_saml_4096.cer diff --git a/.hgtags b/.hgtags index 6a93fa4c..b554d30a 100644 --- a/.hgtags +++ b/.hgtags @@ -99,4 +99,7 @@ cb306bc9c833171c91c68c53af88889159e251bc eumw-3.1.0-RC2 dbb0aaf15106841268b424e0a5a0b3b46bb7836d eumw-3.1.0 6a60d2f37150a5fbf7551ae868bc1d6074ccc8fd eumw-3.1.1-RC1 43ee82a021713ba4a0075638319c12deaeb1fad4 eumw-3.1.1 -b8cd1357f8fa8823a4e035fa769991f13d5a98b9 eumw-3.1.2-RC1 +e3145707b105cce63259d183e2ec70bc1f9f96e8 eumw-3.2.0-BPR-TEST +f001469fa9675ee204d1714f2288b3c0ad1a03db eumw-3.2.0-BPRTEST2 +a307cf05c48d525548123ae0961968a96224e9d4 eumw-3.2.0-RC1 +10b8ac1a45568277afa57411fc6466ec30368fa3 eumw-3.2.0-RC2 diff --git a/configuration-migration/pom.xml b/configuration-migration/pom.xml index bf351f32..f0e5b3e6 100644 --- a/configuration-migration/pom.xml +++ b/configuration-migration/pom.xml @@ -3,7 +3,7 @@ eumw de.governikus.eumw - 3.1.2 + 3.2.0 4.0.0 @@ -74,29 +74,15 @@ - org.jvnet.jaxb2.maven2 - maven-jaxb2-plugin - ${version.jaxb2-maven-plugin} - - - - org.jvnet.jaxb2.maven2 - maven-jaxb2-plugin - ${version.jaxb2-maven-plugin} - - + org.jvnet.jaxb + jaxb-maven-plugin true - org.jvnet.jaxb2_commons - jaxb2-value-constructor - ${version.jaxb2-value-constructor} - - - org.jvnet.jaxb2_commons - jaxb2-basics - ${version.jaxb2-basics} + org.jvnet.jaxb + jaxb-plugins + ${version.jvnet.jaxb} diff --git a/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/eidas/ConfigHolder.java b/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/eidas/ConfigHolder.java index ee939263..f68c958c 100644 --- a/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/eidas/ConfigHolder.java +++ b/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/eidas/ConfigHolder.java @@ -19,6 +19,7 @@ import java.util.Locale; import java.util.Properties; +import de.governikus.eumw.eidascommon.ErrorCodeException; import de.governikus.eumw.eidascommon.Utils; import de.governikus.eumw.eidascommon.Utils.X509KeyPair; import de.governikus.eumw.eidasstarterkit.EidasContactPerson; @@ -127,7 +128,7 @@ public class ConfigHolder /** * When setting the path to config folder for migration make is canonical. - * + * * @param inputPathToConfig * @throws IOException */ @@ -195,7 +196,7 @@ public X509Certificate getMetadataSignatureCert() throws CertificateException /** * Get the keypair to sign the messages and metadata */ - public X509KeyPair getAppSignatureKeyPair() throws IOException, GeneralSecurityException + public X509KeyPair getAppSignatureKeyPair() throws IOException, GeneralSecurityException, ErrorCodeException { if (signKey == null) { diff --git a/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/CoreConfigurationDto.java b/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/CoreConfigurationDto.java index 547df117..284bba53 100644 --- a/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/CoreConfigurationDto.java +++ b/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/CoreConfigurationDto.java @@ -18,9 +18,9 @@ import java.util.Set; import java.util.TreeMap; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBElement; +import jakarta.xml.bind.JAXBException; import de.governikus.eumw.poseidas.config.schema.CoreConfigurationType; import de.governikus.eumw.poseidas.config.schema.ObjectFactory; diff --git a/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/PoseidasConfigurator.java b/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/PoseidasConfigurator.java index 5dfb1525..6208df83 100644 --- a/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/PoseidasConfigurator.java +++ b/configuration-migration/src/main/java/de/governikus/eumw/configuration/migration/models/poseidas/PoseidasConfigurator.java @@ -13,7 +13,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; -import javax.xml.bind.JAXBException; +import jakarta.xml.bind.JAXBException; import de.governikus.eumw.poseidas.server.idprovider.exceptions.InvalidConfigurationException; import lombok.NoArgsConstructor; diff --git a/configuration-migration/src/main/resources/xjb/generated-source-settings.xjb b/configuration-migration/src/main/resources/xjb/generated-source-settings.xjb index 293b5d7a..86e22e70 100644 --- a/configuration-migration/src/main/resources/xjb/generated-source-settings.xjb +++ b/configuration-migration/src/main/resources/xjb/generated-source-settings.xjb @@ -1,7 +1,7 @@ - diff --git a/configuration-migration/src/test/resources/keys/demo_sig.cer b/configuration-migration/src/test/resources/keys/demo_sig.cer index c5d04950..de109ee5 100644 --- a/configuration-migration/src/test/resources/keys/demo_sig.cer +++ b/configuration-migration/src/test/resources/keys/demo_sig.cer @@ -1,17 +1,27 @@ -----BEGIN CERTIFICATE----- -MIICuDCCAaCgAwIBAgIEXJjlhjANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBNt -aWRkbGV3YXJlX2RlbW9fc2lnMB4XDTE5MDMyNTE0MjgyMloXDTIwMDMyNDE0Mjgy -MlowHjEcMBoGA1UEAwwTbWlkZGxld2FyZV9kZW1vX3NpZzCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAK+GajhQAv1Ux2tOMdkY2UUgtWCLTOxnCUn0nQjC -cIXWwh2LPmaU7cjx+6Zb1dcWe7TVKbKXYd8AnwocRkhPZGM1/0vPUVUogeZs5qcl -cTiOG1nqOwFw0lvHT+Wm1raK0V+y2xpIrA+54EKQJkqFGR5hUuemhYet23dL3DP6 -Q5GQFiNFl4ugW0HnhLGaYwNwVQ6xseVjq79Y7daL9sNfTpeP9+Pn6PIKJzPkCDYn -AW1vB+Y1lniYon0g26m/8M4eO2zkrE7TgyJ4ZJI/wqnDErh5pdbwmCeG4MKnXih1 -4mjJnEgeASqjyxGyH2t9BaOrgjcm5B6Fssc4ulIH4IVgFnMCAwEAATANBgkqhkiG -9w0BAQsFAAOCAQEATnlEHATJ2cLxXwB/s3XQz1nqlFndjZdjZ+5F/izc/hXhQugl -uA5uUndxM7B4uvi33OW6d/5B/+Ox3bWLIRo9iltMobCcj6jXxgeWWtntWXeo7tBd -gQ4RsvizaONlZaekSIZ+ksF6O4q4vWuREjhqXJDeO9v1qj1l8PRtOZkRZRiIcJ9F -02G4YTPl0bkWg9yLGw8eBaM9kn8Ppvsvwz5X5f6LIN2rPKHt1NgoO8Pah6GWul/l -CIU7cbCpycoHjd5DZVPNxXHuC5BfQCHCaIuLN3a3l1OLLk0KUtolEsfNbyKDNKVe -HZ0pufoBmWaioncv/G7YV9YzlfuGy0OMSEG1Nw== +MIIEqDCCApCgAwIBAgIEWyjDgTANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAty +c2EtZGVjcnlwdDAeFw0xODA2MTkwODQ5MDVaFw0yODA2MTkwODQ5MDVaMBYxFDAS +BgNVBAMMC3JzYS1kZWNyeXB0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEAsCZtXNuuY6XqeLyIavb0+ZOrGH8WVns4D+zWgrPcvrHTizUX1iNeF1HplLKX +QiX7kXn1t5D4xZX+4tstMNUszsu6DwTzXwK+d2+RpGYrE0iscyaFKyZNqGGtDc1a +l+1r/dh+7IlGWDwyIVUerXKIdrfg9ut+aE0rp1bqe45pKPRlIDDCWtvHh6GkOW/b +hMiLaI9Xdx0H73rWaSufy+IQXYT/XsQ314ZsS6lai5gaH/b8/knF0ntdZ+u/h0ph +kTAPnwe0+0Kv+Yr1U2Nl6Z5edN4WliDQVNT8CAtAneoH4KGfq4we7nRIJ1jDVxRV +L/RvwwdDJOUhHwQFhRwZ7eeUEKHfVP6p+KhzNpU4g0P+zGe82jpWLdBYFfG48o6a +g8/Ki9LyDeZet3PQgQwikrmJhm5VUJTRizBAeEGaXSRWUQWC+8ylCTYKw0y0x0R1 +MHW7KDpOuFAP/iHCexW7qwKUTF9wa6gV79KPfiNVpHhasUHBUH+pFMZTp0sgBRUm +mM/LE+4zWywbEZiU3TxsfPzGNVI77hIXOCAwSzshaw1ONuxdDn+epr11lTpccPFS +KYpK2PpUpDRInxsCDZAmJP+IAem3pKPAHN1iP06BC7dnf48Ty/y9upB0f8wG1xQI +CUFGfmqGI5BuQIJh7uOvFsqS8OYotpwZEeCBnm/xOjgG8nsCAwEAATANBgkqhkiG +9w0BAQsFAAOCAgEAhp8ma76ErykiovjUY9X7/qeT3CrHiimAoSZKETYrQTjPAT4x +qfAEvnzB4MHP/3plUih8NwcKzRWSvmazIK7Inea1EcQzRXvPASfIZY7shBKAgMUL +6KJd07EKio1na9ARwwnqx/2isr1gEc2AcUKP3iYBcYDGyyD7Z2pk28OvaHYht6EK +BlMZG/R1wmmR3nvvEsUahLjJKzPJWjqc8ZJsBHnKK9y7YJpzCJBNpMH8HIZUubzR +JUn/difxp7ARrvnymqg1qIOJ8oobX+gBadb8Mn0UXyuD0MTsJ1gpIURiSNJwUWuZ +q6SiGTf4goCz4WR1QtiAuU/aI3hldXoi+WhEwevGSGiUtdvWW+CkAbuYoPXA8nAS +W7Im2qAvY6jBNHC+Hk1FOqONjK/3FPiQ6i824YdFo5zdF41cWpyFJyShsdJqk9wA +NZucLy3iCiVpCN5OX9Xo8Ss/H4wRN6VMpkhibrj/f/ThLr3v4x0QtFxhX4cDKA5i +u2VS7uACp4lEoGTgRjn3x22jao1oW1lHx6/l7+xzxqb0bSBIaRC3U0fEGW6Jypnf +aC4SrjMLU++lvDESFJe8H+0P8ZmECAg48rK+ez5XGKC11HYWVaXh0gW6wv2rSEEK +IeTjIcSFSFJfKnbG+oe2GzBiIWidhKSyW5l0dqa9sQlbMHtMlAl8pYluuZE= -----END CERTIFICATE----- diff --git a/configuration-migration/src/test/resources/keys/middleware.p12 b/configuration-migration/src/test/resources/keys/middleware.p12 index e09b16c26a6762f1f4c1fd098c9b1d6161a326da..c350c5f746402c04abe4f764b16dd3e55a2b0f0c 100644 GIT binary patch delta 4103 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 BzDEE6 delta 2380 zcmV-S3A6T`AcqrwFoFq#0s#Xsf(bkZ2`Yw2hW8Bt2LYgh2`vPI2`Mmw2_-Os1#t!m zDuzgg_YDCD0ic2fVg!N(UNC|MS}=kIRt5_yhDe6@4FL=a0Ro_c1p6?81otp01_~;M zNQU@ z&{VM5Scne{Td}PlF~;fPgOfs~r!>LKth|6TaN61l?X>_w#AAP&Z5~mQqK`Vui-E0=6 zjij_gk&h&_wl`miWpu*nJC>KsoNPw+f{gznFkP7knDCvDd(v?hvPY%43gfB$^M!$O zE$^x{Gtl=kQBRK%FZvArqI9&e4~$72k^Q|2f~KY5tDqEv9k&YVy@w&?MSOtEMF83f zGJY<9{iWdi>U76}#Da&oYEGJzlSxQs;Y7!2c(T#r-R7N*XgzPPKH}vWA8lSlWrYhA z(c^yj(7|FX?#Zks=IP9nXivr@nxq#=tBrBPPGv{UF7E&>RXQM!pe}D=YR^O0ra0GO zpz2Qnx#B?<_TkZYW7D)X=K`IuG^GFl^|*$Ao+tzd<_cfhbd;su^=93L9Xt3wbAPs9 z2FkMx5cJ7Hdr;aIx^VTSbUH}QuMbar%sS`z2pQT=1$B5SP_|s5vD+`Z|Dj)xVCMZl)7tM8{vW~wex$44ywBZ~xy>(?apRDj@;|N5UKVy)-CxjoA{?kn6DIqEYU`no9fV5AqMK>bde z5R<$xDE(dTizWwEsXP4>NA!TUjJ&D+K-( z(;Ovt3~HAUUBT}?!o>t&NV2dd+{7oquyBr(5(+*lH8(IfH#j&sI5;*qFoFZD1_>&L zNQU9$I`V80YU1I@mBOTXSp&%01kju37=ac`EK3z1R9n^066BV*uFzv?-ETz>vs4$ z>S+VJVYL#Fp~bH)yltZmkT{ppuP6P>B6BfRz)1pNYRLO1^Kyp1=crU zl}yKIrIE@bjGeY3ns1Kt)B_r`X3T$9qA)DTT8D1#&j1GW{pH-{2)&#mZ8E5r&2(FU zw_34oSS}p~kyFWozGqe1*Qk;j<87@(hR7?G6upOs1)mCbJ-G1&Eq-qFy#HSb0@CsE;3nJJ)_9xTt@Em8#6{ zs~BPjQ;dm+r#!Z%yU~v>!Azni+i4e)On+c(r9xn@>$S}`8TU|#==e*b1)Y=4 z<}n)PYUvdq4Xv^k9O2AD-m?7!;lY~^*RvYsGIj6OThy>_4$PLHwh)J2%U#~owJnn$ zbNbZ@PO-B$L-=6Qew0_Zf`otE{{pXrxz-0ggKEzE!O7*j4#JyFZl(b zHsACTY@uj^NY?F@A*xEOR)AUsU>0w{HG55bG?fET89S`f)1Bas9^v7qqKl~|24mDA zbfIZUB_`@xVTH=a?l#sYi3w`puJDN6??f47+25zNm#IQGUPi3bZsmW`wT|8nEM52V zb)65)pZR^HoWNs>JpG|e5S;HFn+p{lDWi3nvGM@Xe)_Z@m==Y3r5 z<*bPoW-`^qdv#VWap!*@R->8kzQxvz`b=`7lSDzUDeI^qq8ve!Mk5@`=L_j(KJ|1s z%JRKq?WiS?y1t`|(NkwB8uC|~ZgH(6JMKFWJH)mEO3${M1RosF?FrUoAB(i-`FRW7 zuOFLy{iFiGW34moN7kmn>K0iWMwQ#ly>8}3a7RqqH+3*RFd;lJ2?hl#4g&%j1povT y8oWfkz**!YmC`XDXSR)#guy*i1Qdc8#Qt8BOTB$K`D|L9T>l4cWwHVT0fwNFhKZK| diff --git a/configuration-migration/src/test/resources/metadata/Metadata.xml b/configuration-migration/src/test/resources/metadata/Metadata.xml index ab274374..7da1ed17 100644 --- a/configuration-migration/src/test/resources/metadata/Metadata.xml +++ b/configuration-migration/src/test/resources/metadata/Metadata.xml @@ -1,21 +1,19 @@ - + - + -jGdILvGbicci1LibGe9lUSSvgIJfu4sivpLq+u4Q0uc= +LMms6+mbhKxlpAFKhfTp3+Dzc1NkFm7XWS6xv1JX/pg= -J13f2PCxRJ99hy1CD8k8u8La/AN8k0u/SzNE7doNfuPbghiC1sLIDcWs+ofo9pRHJWCICX1Z4IBW -RkL1l1o1rVVDdPaWLE41Uy1vuw2qO/79xcVx/V+/ksw+Jkc5qUzjEJyl44bp81FqSz5CrNmL1Izd -cdBw41CrSLeY4gJTtbWgpEQ7r3HsjyIYLpgyk4heTlWhXyJJpk6t8Gqfcs13m93EMS9hzmkxYmdp -2QE9XQoymAhjFuBzj9VVbEjflyVeVoUDK3HKU35sHFOUvhGK6reaGwDwhSjDmOdt2AhNwN4zEwsM -2nAYs0DeC3fo6HCYDUQjdDvNu3SN3tMsApVEJA== +ASz1R4kLVKz0hXukYxotYaAdaRKaaVo50kwXfXE3gYKWYAHX/TzS8+Ef4BdEjcNAZDEIbArCUDt8 +WFt2/47BqCnmAGClS41465529w8xW1aQwSA73cVdjPd2/p4foSXWM80SIW5ut5eQwr8cyqsAGais +2alSWfsO61bW0uvGcRWkJNMH -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:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file +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urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/databasemigration/pom.xml b/databasemigration/pom.xml index fccb7136..73b58a1c 100644 --- a/databasemigration/pom.xml +++ b/databasemigration/pom.xml @@ -14,7 +14,7 @@ eumw de.governikus.eumw - 3.1.2 + 3.2.0 database-migration diff --git a/distribution/pom.xml b/distribution/pom.xml index 2f3f17c3..23895e94 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -15,11 +15,11 @@ de.governikus.eumw eumw - 3.1.2 + 3.2.0 distribution - 3.1.2 + 3.2.0 pom diff --git a/doc/source/chapter/Changelog.rst b/doc/source/chapter/Changelog.rst index 4cfabadf..db442713 100644 --- a/doc/source/chapter/Changelog.rst +++ b/doc/source/chapter/Changelog.rst @@ -236,6 +236,14 @@ Changelog - eIDAS Middleware: Update identglue and fix behaviour for mobile use. - eIDAS Middleware: Add the shibboleth repository to pom.xml -* 3.1.2 - - - eIDAS Middleware: Fix CVEs by updating affected libraries, most notably xmlsec. +* 3.2.0 + + - All components: Update to Java 17. + - All components: Update to Spring Boot 3.1. + - eIDAS Middleware: Fix use of P12 keystores for TLS keys. + - eIDAS Middleware: Fix display of CVC availability on the status page. + - eIDAS Middleware: Remove deprecated configuration parts in the documentation. + - eIDAS Middleware: Only accept specified cryptographic algorithms and elliptic curve parameters. + - eIDAS Middleware: Fix generation of sequence number after an initial CVC request. + - eIDAS Middleware: Improve form validation for initial CVC request. + - eIDAS Middleware & Demo: Update new references to the German eID client. diff --git a/doc/source/chapter/Configuration.rst b/doc/source/chapter/Configuration.rst index 2987c8ed..0d7c2027 100644 --- a/doc/source/chapter/Configuration.rst +++ b/doc/source/chapter/Configuration.rst @@ -15,7 +15,7 @@ The following overview illustrates the required certificates and key stores. The following table describes the individual key stores and certificates: .. table:: - :widths: 2 18 40 40 + :widths: 18 40 40 +--------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ | Name | Description | Where to configure | @@ -23,32 +23,22 @@ The following table describes the individual key stores and certificates: | Server TLS | This key store is used to setup the HTTPS port of the server. | application.properties > server.ssl.key-store | | Key Store | | | +--------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ - | eIDAS Middleware | This key store is used for the SAML communication with the eIDAS Connector. | | - | SAML Key Store | | | - +--+-----------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ - | | SAML Signature | This key store is used to sign the outgoing SAML responses. | Admin-UI > eIDAS > Signature key pair | - | | Key Store | | | - | | | In addition this key store is used to sign the SAML metadata of the eIDAS Middleware. | | - | | | | | - | | | The corresponding certificate must be available to the remote party (eIDAS Connector) | | - | | | so that the SAML metadata can be verified. | | - +--+-----------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ - | | SAML Decryption | This key store is used to decrypt the incoming SAML requests. | Admin-UI > eIDAS > Decryption key pair | - | | Key Store | | | - +--+-----------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ - | eIDAS Connector | This key store is used for the SAML communication with the eIDAS-Middleware. | | - | SAML Key Store | | | - +--+-----------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ - | | SAML Signature | This key store is used to sign the outgoing SAML requests. | Admin-UI > Connector metadata > Metadata signature verification certificate | - | | Key Store | | | - | | | In addition this key store is used to sign the SAML metadata of the eIDAS Connector. | | - | | | | | - | | | The corresponding certificate must be available to the remote party | | - | | | (eIDAS Middleware) so that the SAML metadata can be verified. | | - +--+-----------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ - | | SAML Decryption | This key store is used to decrypt the incoming SAML responses | | - | | Key Store | | | - +--+-----------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ + | eIDAS Middleware | This key store is used for the SAML communication with the eIDAS Connector. | Key Store: | + | SAML Key Store | Especially to sign the outgoing SAML responses. | Admin-UI > eIDAS > Signature key pair | + | and Signature | | Certificate: | + | Certificate | In addition this key store is used to sign the SAML metadata of the eIDAS Middleware. | In eIDAS Connector | + | | | | + | | The corresponding certificate must be available to the remote party (eIDAS Connector) | | + | | so that the SAML metadata can be verified. | | + +--------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ + | eIDAS Connector | This key store is used for the SAML communication with the eIDAS-Middleware. | Key Store: | + | SAML Key Store | Especially to sign the outgoing SAML requests. | In eIDAS Connector | + | and Signature | | Certificate: | + | Certificate | In addition this key store is used to sign the SAML metadata of the eIDAS Connector. | Admin-UI > Connector metadata > Metadata signature verification certificate | + | | | | + | | The corresponding certificate must be available to the remote party | | + | | (eIDAS Middleware) so that the SAML metadata can be verified. | | + +--------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ | BerCA Client | This key store is needed to access the :term:`Authorization CA`. | Admin-UI > eID service provider > DVCA client authentication key pair | | Key Store | | | +--------------------+---------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------+ @@ -71,7 +61,7 @@ They will also provide you with their TLS server certificate which needs to be e Be advised that the Common Name or Subject Alternative Name of the TLS Certificate must match with the URL of the middleware as it is reachable from the Internet. -This is important as the AusweisApp2 will check the URL in the authorization certificate against the URL that is +This is important as the AusweisApp will check the URL in the authorization certificate against the URL that is received from the eIDAS Middleware. E.g., if the middleware is running on ``https://your.eidas.domain.eu/eidas-middleware/`` or ``https://your.eidas.domain.eu:8443/eidas-middleware/``, the CN or SAN of the TLS certificate must include @@ -187,6 +177,12 @@ as it will replace the existing configuration without further notice. We provide XML samples for both the test and production environment, which can be uploaded and then completed using the web interface. +The XML samples for the test environment is available for download here: +`Samples Test Environment `_ + +The XML samples for the production environment is available for download here: +`Samples Production Environment `_ + .. attention:: The upload function is not designed to handle POSeIDAS.xml from older middleware versions due to changed data structures. It can deal with exports from version 3.0.0+ only. @@ -217,8 +213,9 @@ This section is for management of :term:`eID Service Providers`_. @@ -173,7 +173,7 @@ Scalability The performance of the eIDAS Middleware improves by adding more memory (RAM) and using a faster CPU. In case the memory configuration has changed, the server needs to be restarted. To start the JVM with more memory, add ``-Xmx`` with the new maximum memory size to the start command, -e.g. ``java -Xmx8g -jar eidas-middleware-3.1.2.jar`` for 8 GB. +e.g. ``java -Xmx8g -jar eidas-middleware-3.2.0.jar`` for 8 GB. Request Signer Certificate @@ -277,7 +277,7 @@ Optional property for ``TRAP`` is ``poseidas.snmp.managementport`` (port 162 is set). All existing SNMP GET values are explained in detail in the MIB located at -``https://github.com/Governikus/eidas-middleware/blob/3.1.2/poseidas/snmp/EIDASMW-SNMP-MIB.mib``. +``https://github.com/Governikus/eidas-middleware/blob/3.2.0/poseidas/snmp/EIDASMW-SNMP-MIB.mib``. Global GET '''''''''' diff --git a/doc/source/chapter/Requirements.rst b/doc/source/chapter/Requirements.rst index 14b33698..305c2db5 100644 --- a/doc/source/chapter/Requirements.rst +++ b/doc/source/chapter/Requirements.rst @@ -9,8 +9,8 @@ Software Requirements --------------------- The eIDAS Middleware is a Spring Boot Application. This means that you can start the application with a JRE and -there is no need for an application server. We support the latest available Zulu JDK in Version 11, -at the time of this release this is 11.0.16 +there is no need for an application server. We support the latest available Zulu JDK in Version 17, +at the time of this release this is 17.0.9 For the operating system we support Debian 11 “Bullseye” (LTS). diff --git a/doc/source/chapter/application.properties b/doc/source/chapter/application.properties index 5baae93e..81112f93 100644 --- a/doc/source/chapter/application.properties +++ b/doc/source/chapter/application.properties @@ -13,10 +13,10 @@ server.port=8443 server.adminInterfacePort=10000 #TLS settings -server.ssl.key-store:file:config/keystore.jks +server.ssl.key-store:file:config/keystore.p12 server.ssl.key-store-password:123456 server.ssl.key-password=123456 -server.ssl.keyStoreType:JKS +server.ssl.keyStoreType:PKCS12 server.ssl.keyAlias:alias #database connection diff --git a/doc/source/chapter/eIDAS_Middleware_configuration_prod.xml b/doc/source/chapter/eIDAS_Middleware_configuration_prod.xml index 9e6b805f..5cdcd46b 100644 --- a/doc/source/chapter/eIDAS_Middleware_configuration_prod.xml +++ b/doc/source/chapter/eIDAS_Middleware_configuration_prod.xml @@ -13,17 +13,15 @@ blackListTrustAnchor - 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 masterListTrustAnchor - - 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 dvcaServerCertificate - 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 diff --git a/doc/source/chapter/eIDAS_Middleware_configuration_test.xml b/doc/source/chapter/eIDAS_Middleware_configuration_test.xml index 5bbaa900..5a6950ee 100644 --- a/doc/source/chapter/eIDAS_Middleware_configuration_test.xml +++ b/doc/source/chapter/eIDAS_Middleware_configuration_test.xml @@ -28,11 +28,11 @@ masterListTrustAnchor - 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 dvcaServerCertificate - MIIKvDCCCaSgAwIBAgIQFKaXeEa6YGAo7Jh5L7cTgzANBgkqhkiG9w0BAQsFADCB3zELMAkGA1UEBhMCREUxJTAjBgNVBAoMHFQtU3lzdGVtcyBJbnRlcm5hdGlvbmFsIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxHDAaBgNVBAgME05vcmRyaGVpbiBXZXN0ZmFsZW4xDjAMBgNVBBEMBTU3MjUwMRAwDgYDVQQHDAdOZXRwaGVuMSAwHgYDVQQJDBdVbnRlcmUgSW5kdXN0cmllc3RyLiAyMDEmMCQGA1UEAwwdVGVsZVNlYyBTZXJ2ZXJQYXNzIENsYXNzIDIgQ0EwHhcNMjIxMDA2MDgyNTE1WhcNMjMxMDEwMjM1OTU5WjBuMQswCQYDVQQGEwJERTEhMB8GA1UECgwYR292ZXJuaWt1cyBHbWJIICYgQ28uIEtHMQ8wDQYDVQQIEwZCcmVtZW4xDzANBgNVBAcTBkJyZW1lbjEaMBgGA1UEAxMRZ292ZXJuaWt1cy1laWQuZGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGgAh98Jn3qIhyIm8U+0fm0RSSxXev5GkblQO5SWCkZvTV3NZoX5voUzux4sUe/HfK7I5kMIory8MqXzcAovrxKyEI+Ia/X3ww6mlAFshQYPFtrh++OALXVkM0sL93qh8fiGe4ulHMVeWT1YpKOofr3OLgQqUscGLAjx3d5EnpVavRmEqaj0ghWzCP+TEEfxqSHd0SnCOE9M7pgMWEYdQbK8Fy1NYjGjIjpoGhKUG1FpWby8x3egSQJU90I/NI7PKptZp++usVYK/aALCrg1M1F3JpWqGO2A/kyx00i7gLf935Whf0ErVd46xYdyxRcE9GQ6ZREjSaGa5bDfiGD8slIeRBDGRpg83insT/j45KmChaGsVw/xkjnbebC3lt0IcoyV62PTyCuBRWtSQT7DZ4Oc/ivQDPdlA/glyeh2Z38imLQNm+TmlJU7qLgmY18JXIVvHMwwLOQ9ouDIckPXyQFLiyhk82uTtf3sgPsBeOEJPAaGmNlC0mXsTq0e8v9XWmIuYCbg0mttBGjD3vfPD0ZZgaYDbzYSXNqfxs03geMOB7qQVBeGP7OlUK+L0YH+JIhdDd1AdPz6G6Sg8Tx0gBlJGHFK9kPscF2InbKGQ+AEU7TbsSjie1Gg+UmZw4WrPOsZWr3UOxMDb8Y916UAJWBv1HEtj/1FetOIjnYIP1PwIDAQABo4IF4jCCBd4wHwYDVR0jBBgwFoAUlMh0RvU6tEZIJvgryjQeViYEEgAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAdBgNVHQ4EFgQUQwm40KqaCukVy3ci/g8YIEsB+JcwZQYDVR0gBF4wXDBQBgorBgEEAb1HDRcBMEIwQAYIKwYBBQUHAgEWNGh0dHA6Ly9kb2NzLnNlcnZlcnBhc3MudGVsZXNlYy5kZS9jcHMvc2VydmVycGFzcy5odG0wCAYGZ4EMAQICMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VydmVycGFzcy50ZWxlc2VjLmRlL3JsL1NlcnZlclBhc3NfQ2xhc3NfMi5jcmwwgZkGCCsGAQUFBwEBBIGMMIGJMDMGCCsGAQUFBzABhidodHRwOi8vb2NzcC5zZXJ2ZXJwYXNzLnRlbGVzZWMuZGUvb2NzcHIwUgYIKwYBBQUHMAKGRmh0dHA6Ly9jcmwuc2VydmVycGFzcy50ZWxlc2VjLmRlL2NydC9UZWxlU2VjX1NlcnZlclBhc3NfQ2xhc3NfMl9DQS5jZXIwDAYDVR0TAQH/BAIwADCCASQGA1UdEQSCARswggEXghFnb3Zlcm5pa3VzLWVpZC5kZYIYZG9ja2VyLmdvdmVybmlrdXMtZWlkLmRlghZkZW1vLmdvdmVybmlrdXMtZWlkLmRlghpkZW1vcGFvcy5nb3Zlcm5pa3VzLWVpZC5kZYIZZHZjYS13MS5nb3Zlcm5pa3VzLWVpZC5kZYIZZHZjYS1yMS5nb3Zlcm5pa3VzLWVpZC5kZYIednctcmEtaGVzc2VuLmdvdmVybmlrdXMtZWlkLmRlghpvaWMtZGVtby5nb3Zlcm5pa3VzLWVpZC5kZYIeYXVzd2Vpc2lkZW50LmdvdmVybmlrdXMtZWlkLmRlgiJhdXN3ZWlzaWRlbnQtY2FuLmdvdmVybmlrdXMtZWlkLmRlMIIC5QYKKwYBBAHWeQIEAgSCAtUEggLRAs8AdwBvU3asMfAxGdiZAKRRFf93FRwR2QLBACkGjbIImjfZEwAAAYOsZhwC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 diff --git a/doc/source/conf.py b/doc/source/conf.py index c5648ae7..e3580d28 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -55,9 +55,9 @@ # built documents. # # The short X.Y version. -version = '3.1.2' +version = '3.2.0' # The full version, including alpha/beta/rc tags. -release = '3.1.2' +release = '3.2.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/images/Certs_and_Interfaces.png b/doc/source/images/Certs_and_Interfaces.png index d001271c6b135cf3d5356667f3bc525a1589e65b..a76e30e0ce09175729b2c3c64f3bf0ab21ee4818 100644 GIT binary patch literal 117835 zcmeFZWmH^Sw>Fp@5=ekR2*EA5yL*DBaCZq1+=2&BLI@543U}9nAcaeUyE_F0cPqTG z-f+&j=Y78(_r9b1N00t-Gsqa5qN?^@bFOL6eC7&LQjmUzN{IU4!GmX@w-PE39z2FU zcz`th`$$^vv~hv|u}P~lBoY#mLdq{6 zsY$54W+@HSlz8L!@%LxmKQh@rN}4EP;jpSHslC)Qxd}@A*iQM)A~Rq4P^`Js%41`* zAT?!kdUJCx!F^%f`=eQ5QBl2lVdBMgRlUxoFL3w!f4>D1b^gA7P!N!f{?{*`P`-m7 z{&juuAd2Jf_mI9;LH_IdC(_%VzhD0N07UTjHRdaNq`$6zKcq7K`(>d||6hGMRSbB# z%%n5z?#{_lR~<^eu6LL3i9yt+ZT2+Jfa{-@ZT9FV<|x4B>yAYU6|+O(nK@rE2?+`3 z*N63A?w|BMiUO5s+kRfhZ9rgP;KnDnUPHY5<-8(#Mehf^K46^#mYIEG(>Rs(a~m5x(tt zMM067Ms+VhZ6pu@@X6!oKW}RNzc>9~@&4~d`hR3HZ;!J3LIhVPu&_pT92hE67m}ln zs60$71W#>QgUImCU`~T+9R4JNuKA)FKgj}1rLL-kjCHqPR9~)%%#`^BY{19 z@Trm}$6R?J`ZrGh-c-oGa*~YGO`E!?5B0Gs?oS@{b?2{<7(q+$w}XM%q30)N*GME3 znYZJ9gY~NJxQ$6iRCRVyB)W#eoC3B7T6#COD5t}|J+5g`!)7!ZiVlrq>~BtqEpMeS zJvc@7bOAC0vjTDyTHod7wnZ{9#;o0alk245?k1IVR{u~*8dh$Ly8t{6@3U~^} zEH-~Avv(Uvt02R^C_UTV2IV7%|NL{UAi&#sZWW$T%q7{+nJ?;QWZK4z_`9xPaF66&!1&_+aq+?hP~Vo*4x_~EnOD^gTa_}tLV7NbN=s}Q;v++W|H*! zt*1kPPI!FNKQ>y|C*NbU&~!axUAjA76esi=t-^dT{3_)!J*|ltlzdX2=wmw=Vaiz? zvNZFtqxXGE{tLu3`*Q9vprc*TwgyFR;5c358?Kv|+bW=NVGVqR(nt>U&zX zo=y(b4QPB@y|Ay;ZXOoU2=J*~Td}wfu!@_9X!I&*3Q>!yB&BsUVOI`7t;ju!{;}8I zw(P#NFVW|*VDQ%))(RyJjVjmOnXun1)iB49HRpV@soRz;)E=3ch@HIVUB|W$hdee( zBbhzr8s36#DV5TpH6@a^Ir%V`ktf>}M%N<*DHyhNO!fp@Qv5oW)u(gjd*%>Js8M@y zNwhTB*^+i*gnnZfAmAIt{rN8$rLzesQ@;>w^BqS^eP8m#_?5}Bz zzkXKMN%MgG(8AR?n;^Z7oB1-$ENc0T(zJg@z;>iyCiDm@o@bQ(z8Gs59xUy?tk_ z_u`YU8dCE}ZS=u^$}3ssPF_)EC$BF$Ev?<*h3nMrR$FRnrSar!#U|Gal zbgQz;*+WW5h~ChBcu1)#$nG=s4a~3Fw6?us(w?t=GmEI03Cz%vePz`Im#z75ou{K7 z7MoNgeBcK4sRF6c%(?s%mk8p(Sj}-a7lXbmT0hbOdx8&TDyyhCE_k06;5ohy25rW0 zC`WV5neW<{s5T#e4Q@mP!$-D)fA&nvpy7C)b~ATv3;D$74_WWwn-*BefJ4UnFA{%g zk{M2w#KcCcx*byG_)Nt(No-J0;EuQ zIeYGZdhAR2LbxT)7wo?#Sh&NB&s|Ej75FR&FLSM*2s&#Jg?F0=hPm7HFj)XbZc@vMBqeo^?`s(Eve zO>gl_P~)JG&Cey1P_bdPI7(C4l=qsCUugni39M}%Su>$TF@=(6((UG>H7--tefH8F z;XL;hSwA!!;@nO?sTl3e2e;xIj+V^uvCqo4-&@J(VD_Uhw!}`-2z4-Euux^d9bdqo z`JCIKFouOUvnUb%wsK)T*};2|WZ}bTaXu&k9|gzcEHUHWEz<09TSH|ow#g;ZJa!{| zpRq#Iz*sEadXQqiGZ}3oguB(n+J5Cp+E*vyu)|ZUsT-Z@A zW9^!y%{4B*)zH9P=QDiB328BNjW%N}EjLKr&9;Ab=A!zmtktFUwg`GDJV_T?wJRR- z$k-*vb5K7sX0I*;T1ay|O$Z{eo{=1!>1(D(j7)U~vTXd5&~Wh5n;fi*-d?m}D>5<9 zo%sG@Np)W%$f3ywQ;9=K^N7`^s{9X6Vq75`zKf9^D)k@&ccKCEwZyu)+&xOvqKG-& z2A1swYFb|N-#DF#jLxYw_4z}G?@n@qfY5=W@6zzZ2JG0%b28T++&D;TtxvV%xwm*C z+gcE9rz*WxjXLj0nw>2xxV+3zv`sNTAva4~{dT^IyoBqvDeV`8CQtE3l@kR#E$0k|*2bdE|sW8HF z(P(pYkbo5yI4a^ zS1MmH2g7x7i7HyB6nn-N_{5nQ3h6lUs&ESmcd6i+{D+BnipQ8>#TMHZiEM;0Y4~u0{qYW zYFBVqL#k6cF}FGG_4<#Mmkyj9ox)a>VWkKrd4*`b>rDd2q^(QtG-Z-8@AcY+md94w2{l_RA>v-d{Zjg{a&O=H8F^rjO%xDHq9?G@}=r`s$| ziUwO2;OaEq+RqSZT6>Z(96b?e#YFADH8w9jChkEfw#u@eLzuK3eK&Tq4TDA#PKP}E z?S~3e!S0CW#i)$So+$ZSv^ew`af4(E16Zv(OCp=DZFZrQ^|(}1&H7+@%StVlY^fGA zT2dsq%<11F?PU~)0OI{mVUOeU^W}(f)9-|dB!$l!yn?mLY{lJj^d#upNp!YLvE_SK zaQ%U(>~h|?MrsUJ+nG}Y2Y&3XvzwEQt|R8xd&Ey+7il6r+JkTlI*i{# z97ubWSU4rPWIxx^;tGMwpdr;evaC%Dc&3owYK*N0&Ye`3F}7W!Oa7o`d}P%xyKSFr z^vHe<*yoMUc7kEZhTaV-ow@h^wV!lTp1|ZzKc6l1%VrPZmK7ZjN@3Lsy~D^%82T%w z*=)v`cNR4^D67#%P+$d9GEu?b#^@w*;EBk;wO?^BcWe$!R^ClUs?-M&2%?zIHNHQ- zEAM|vG^}c0e3s7n!KX%>k==*3(4!XUa~XAxV=&FX^SyDbr%u-=>TK?~AkLQb)><1- z%(var)iue=icMcf<2Y~Hu1VHgI!?-GmtS$YOYcod+B{W3t5{v@rLy@!s?N46yglmD z^wOzRjc9mXZ2lP9kO%s(#*HO=qF7G=Jk0-LKHT(KN3EEmUdO}IR`l85%mS={SXRI7 zD<1>qtn=NLEtx<1^6Lr zGj8C*_kHBK}CnzRg3 zLKkA;DcBcnCt&Z+BY%n1Rj_Njp~}9m#44mc^dNpLcAXd!+ri>?eB{+^&GO!1Hcsuu zSF!C74>yij!aHMW8Mrr=RUf3b0+5!V=PfBM+1Odb;o7#wAH%MEdw~`162gixzO8$X zV;`I-5#6eaJyZO2+k4bme`YgF{Y0xMB1`WGRv1}o`0q6noVSvR6dqL?CzL)u;ZNca zC^y}wmCmeHP(ls+p}&S#cM2}u-HG8Qq9Ar^&`_dF8rgrLow1xvN@Xn(THfL%tI{#Ro{9D^h0l&c&!;3VLAB9n zG*cISAO(>vn{{xsntx3JN-!`dX0YBvY*+iBy*6_19kIhPJCZ?NO-p3u7kJ*c>@1XR zkcO<~(B(4f7y=Jrpft;8FH(%O_WlxT*FNvfc)G`XzEzNsZms#PU8%Vu-RPpYT!8=j zhkGP9J$9BDZ1Bgz9~XJ&7$}kvqDVk3A-`|?IsyjI3dnW64>A^~Z+Weq?u~+`&bWTD z(Gl(>sfr*-H$%{wDD%-{J1I>~R~m;NMQLwi%n~@bhQIY4QUP3M0?{z0lcoyI&A+-P zvYUXbpC?7Kee;)b2Xb^zsZFK2XVIX&d+NO|)i=dBF%(8N?=%Jmn7deQW+}EFv-;cW;#OIkGEa`%Kcia^<{Ay2 z{v0RY-QC}9uMGQPtkL|KgTs9pL5+H)3d5g&~WTUcYcnK+@J>bizYTu87i)Pa-Y&gHa!jpERC z>q)9=OBE_(Za7A`IA$%04=re%Md3{Nz9>mwfW4Aq zZ80+sNno5)nJW37xt5MTxiP=PZ>h)LRVhvD;h0?kRb3!Pk7O^UpB?kaQQ@#etU~YW zlSxDGlNcS;lIXs_Eo8WUNhV?Vd58pW$rLBWv{5$OABV`2FnLBPVODME-j5V4^P|9E z2HjrQ64b#bSqn&}a>qnx_xkF`-|QAwLB@98T!!=a>2q5s?Cqr-2w@=mKi!u`s{E}OV0Y1v-x1^r2r`tr8s;p?#gbacKX~Zwx zN{gqT&tbDh$v?I87RdyBRH8f`J!QiVrlVqET`zdFuz$uv`daYXN?c zyo#f4%O4XdBr~xnWcLuJSq;*}FjN-8rv=}v7 z8b$rhn9psOUhqPDQu3+%GZc)tn879k=1K1xBHIc371a)BiGY1kwfbW_s7{o1`xMG> zxDTH!sS+MHGV8)N`)d{wC%ycYuNUxLd)@->U3?SX;*yUt8sQE~{Rh9?D!J_o{KEl^ zUp0zjiFkah%+R$|k85A*LMM5!pJb#k-z-ldE5|;>$t0k}k)?uCQA4z>=I`yb&3*R# zFboeI<0@$Pe&J%-IydY^sS_Ifk~uzIGcXZsIbC6Lu_v5Uf5KF>T_|b*Y+_`=M_>dk?gE{yM(m1x|*}k82HzwY!qhxYQ914wnf*HsGOtN4fr@ z8gRx+3h2qvs$)%ZJ3)c`MIF!jyZdd0^OHnwEdU%LEm!AsL&@cQ=o?Oj@xJY=%`WB) zrQI;z`SbBoA8yB$t`tGH!rq@QQ3RW2witCaB=rR)THLPrxY>jJSePz6KtX^RTmuvY zt|~Oo_pj2e*8|@(&`JXsTHR?IQagR7mzH7~bN|)bosTFuE@z3hVw7|AZ+qS?88j;x zlp76Me^2I~(3(+G>3Dr*#%!B&VmoAJ@ci(7X6{Ruw*BAb@DFH`)EpEXqP?~3_nx~h z!s`__HUh>K+;2T(lL<=b_`UmfjqEJ*Cb61wi?!BpelSN>J&XA&#mk7wv}z9=Vcx^~ zL_L2&@EE)eKo1=s|MDIM@?6}Np6K66)ba7DvnIqYk_>V&$nN0A12@*L9Oj-%7Ga9D zpA&QN=!sXiJM^sSNzR2l%U-)f1#o9_KBFd`+G*?d`2Z7zI9aI0AdNN5WiZREE?v$> z`NtAH)J)H0|C_qE22fJa?uRLMjYe8b)X}*EjUgG8wc_nWp;I*b=#b;-8eAChR&d=C zjKw3XcBNc&s&Ld|b5_jZrg)15tzG;0G)`Q%di3mV&v_D+IFNe1RIiF%`1n1FW%Ujy zU9vw3_GAXCNeQ^aH@cxb2n*;4`oT-IU~a4UQ@~M@Rsg1kYr^e6*rNIH6lk z3q-WnQmGABvzc@|;vjrKX8Bo%`d4%7`KY)eF7E1(CrCgXr}dq#Q`OI|KSZlVwC)$J z%5UDVXJ!BqJdbBsO+~7f(_wTH-X!*B0h!+>MyjL#JNrRFTsJDONCwL|D=v0XQuNDh z(U=QqEFoSOb^T00^C-gfqZvhVH-txW1PVgz;8zMF^w^%f#R93|1m9>Iw&*C1V1G%S zJUgq5egWl6SCa!&!e8maV)nbo!ciPI9g%nGLbvz2BEGZfIiXLrKELN(`XF-Le2|Z? z*b;8l8mx`PioG2kmoZk-xljmzg>Hw#*SK;PRyx5eVMhd8f**cKT$9TL8Jnk}pJ^xer}za6kElNSyN?+=L{qgl=5t$E<<;oAkhDbs1o@74#>#2C8^PmPtAoCj z=3}G|Kl&a7e|Jf19mk0fmMwv9NkYBmIkbHSRG=VlUj9pVKfK16T?*y-v*2qiRtbN>Dv9oz1o`|)?GsxSspH*Kb;rmX%h^p&D$}d5 zqYOf`5_x~CLE$r4HYgeu)m1-_I9oo6C(Q>@pn~1-1!$AnT4m?G{IBlZ4NZwQQ4_zy zP@ci%vSF+2F0Cn{A15w-j6Y(|6(PPCKt^T1=ed)Hg|lWr&nPFVXlr}q=IBw7YxYRd z0#b9CPHSrCAvK>4e;xc&}R*|@rH5-(3n#krP}5hX7*i_@0K|Q ziO@UlGlxS{nxs`a7VbJ(F-p7JrOgIq#_gXTBCWXpYysRi{`BNe*}K*&fS)I=42nod z*aJNPGbe07%yBkj$1#x?-u69O)x~-S_{OlwSRnWHw_nX1fMWUkoq>6GHsb8{JgSS? zJdGqCV|8w+emVmHI=nqA8#rmBSt*Vi*>QHCEvqGpd@Oy0ykP(yiGaF~h_OENCQt;= zX?>_*vcad%^RII%N|u!Ed@C1-_|lr&y{v!aY9YXIw5tQaHW8YPEaNOqsm5lqUM4FYgu_@kcQ5>40bcRe#v}#Qkp4t~}A;fP1wTEf? zL=MVtYcaFduuaT3h3fUb?Lj9bH{ax05I;`RHT8eY8!*2|ZjKbQiJsL0KPg|yR~565 z;Wu4!{bU3uN1JI;UqofEoZe34uu`ExrkClFOQ97do1;GKwQts!*0yV+WwEh%tY;DZwS7kXV!Q=T(4TZJ(h z9>pR7z*)V+VA|?zw-e<=oiUUt)B{b?+ziW0)wNu@&p zWhk0sTU32pVqBp##AqzL@1b;eec8*C%O5IWa2bWi2?$TxT}LDIen$gzt;?;9nOJ7s zy{5}O;nOKfFS8$PUgsZ9RGuBYECK!+1qQ*Wd{4iz%fd)j;ah zAao^v8(oT-Ol7WSi7qlHCrd$ZV$NIQt<@xalo*I}GPsZo##)%EA%KHkuV&D;$b`z8 zoZ^!-^>%#dGJx+9T_XtZSNa|E`+zEujf`L;%QqmWRmN7KPf<04>rFT2ob@o~+4=G> z&E(|kT#|wae1Y72x9F=?Y2)e4&UA&WtnBK?>VqM1OvzL3gBJiBBraQSiRPjL6Khx( z;Dbz0e-&}x1(uUuVgbX5R#Gu*S9KhIDD6LQaQWS9woGS@yRXWI*@@SBJ{EAK8cAiZ zxXvI;-*z22z$L=t@UIi)6_{a>poHzo?#Z}$X0li{JqA{P3ps(il^&x2e#Wvb*sX~I zEv&6=IIp{UH3lv&a!64doZ7`kYg*`8plgp$Kl=PHmEu?Vew?eB*>qt)1{#c33p|z6 zcS#BnKvl6HQ`!w-ZK~O;+x9ryV^$=jsdL+JGU>!{l0SG3tc!Q+ts?h-@k&zUg|0BQ zJ8RTC59XV@E{%^T?<)8(OqQ9Gx0~J=arVBqg*x)SANzqG-=wZ@EcUjBtFn2*@a_<| z*Fu=~rS15wvz<0cxI4bKWN z_1m-RKg2L`(VC)$tdis77+gpy1gYrac~~p-Ol>}(GJR=#dKaF*0bCg(K{Zc!H!Y^< z)j>mpko)PA@(+t*&=(&c0W=&U&+NP>Q5^F1i$@2lv_rRcHwxe697>tbAQW(S_=0jO z?6b1>Cd%$`M5TGNTCZyMh7Q8dk(f7!mR&z7DSwxhY{Kbwp@q7-nMsqY9Fr%SgW|RD zs){zt7hhp5{oA0}II@Aq@i^WFObm>eVX(5%)nK5cma4^DpziG)RMDJ-R>WR=1B&^& zY}WPDvyB{1h}}q)kR5tGm%m3{+K+V-hFVWX$D2({b6g+RmfO#~ffJf%yp4Tr;4EF! z!fkB|K%RL=tItm1CB)aZFpSqK9fg0!lxzVtBCp-bH=3m8%$-yuj&qftHRTEnd0Oi% zfbJF0%&mh8x$l0pBJ(~TzPdPKWL$Nc4h{(c8p!%khghNnS#Ob8V-)w;{%EPxAm9dA6bpn^rBRcoA#93Y zbscCwaC==yU%;a0{Z>uU1Sq0jmgTt2_fz4pS50-x?qf6x@1jEN{RrLojkgqxzwz*v z9Xs%|+SG@`j~YxuLS5RoGhYC8ut5gUVE^7&DIOjZY{aqjdkFhW`l;(!}EG?^C8}v zy0vd+FWLAZa?$(xy;lv8PVnip*Nbw3H)^-pC zNWev|h&$gBJ)#6Ly66MiQ*|WO)i+h!E5c|!G8D|rg-q7dMJD4@832y@qv|_quiHK~ zk1cbxRkIoAjAeLldT11{;YI-$mitUC!)~{)HBvw?Lf@n7DPQ}f_ZU6A=Z}8J?$_|GXb=21 zzt{Fxsa`1~HB-sYf%=AkWYCb7b%jEw5fd~OIfiyD&`4`W#;nxLAYJ%+;RAH< z`hDEQ{&iWQq7`G4_BBN7uq#^Jut-5UsBeoWCbFy+Fi<4`;qn=oQR`B+Bvu~FmQyQE zs%Rz(`xR-&;|Es9ELLYG&XG6v^0WRnTcFTdDk0fDmQ7(4^1&c+$Z( z`w}qt7X;0B-zyu#! z3#+GD9$WwIEVKGtB@#Sr(j2)wCYpD9SPEZc@^5#HMcLM|d=D7TiV;j#ZQwl!&as{!*|Q4uAxm?Z@YrM2&MRO& zF1YRTbm^xKcm5>dnUWa=K5S6NxI18o6|&x0iJ!XcYei-fq3Ow_nILg&J^nQ*_pF&sQpB+xr$Qn_B*;%$)fW*Jx|W0%K%BGXTG&%ga(n_bV}XHuG)OF4IB zM0#KW^!&=`#7dV`_(?w1Dm`UwkC+4ETqtK|u7bMT1z+fq{nNOyQ%plTmaWN&Zhmg~ zYP)6>i*V&a<8!-(L~yN{?Rkp}^Evn#RtK;Bo!$xcY8bevKjS7(x7A?2C58g!z16!d z{zcg(=sRx{SCI9!RPU~AbFI4dtcaep&D<4r$2^&&@@OdOQKy~n)D8S$rRutWtOCEd z?Wo6-j<5$g5HbIygBbnbYjQ>fLCp!QOH2JR{N#3x%G?!i<4UrVz!$r;Wz8B{Z;}>d zvrNah0QwjDe4tSY!T9yc1^bd2YDE!GZ;0LTqyr|^Rwp$Bey6%R_KfbT>(k+|RiWZs zXIpsg5>@U-3(ZgfV30vTp)VgS#*M|ig1Z*CKR>F6PpMOsAR@!G#V6q9;1i*W!C*5h zhVk`Pjy@v-=*YO^V9md*oIYu;&4q5Ma&PpQ>=s+Y3SaTi8U&{I!fe(L>$_VxF}WvS z#*VwtZ;q6h&4|=WW~7xbJt)fCF*T^}#cB=9p_mxKEF3j@=tLqetcIOoW~c0vgb2JO z^hk9LY%&4Vn|stYCkg8GYfXzPd4hIF@8PKbs>R+c8Ocu{+wiwZPkwWUjgLBKdy4cS zk%j>zYTQyC%Grji2rU1JY&j4bKTcO|@9Lvq+P*m1BG2vu6p2uVC2_2^rx+=OC5B3L zl&vBAV7%akgZ$*z%9ZchT4hws0Arp1oY=&H(Y!D3KG^W&vE(x1WF^Q>*wtFfkGW?B z-M`uMjjpq&1;%6VCBHvQ?PtL`y!K$~3cQ}`0Qu;+wvbo1!Q+l~&&r;98z@>|1G#mm z$m35_Y1U-1G3_F8RZ+TzmnD#E<%T01ew>is=Z3xgkXtUFO9~piwA8?#?LMRqQ4Jg7 zmcX9ye3aMs($fW@4xb4Q*^dH|IdpZ%{d5q0-+m)*>LBmj+vi23csC}PS`Uw&C8AHPHR`F1Dtw^^-B>)Q*&0K`$`2?;fQmMElSV>~=Q zI66KPV5gG_>^*|$l0k>K|6<>(yevH70}Y(%30^*MGEyDZnQM=}gV~88gAEQIpwiJ! z3x57~lG(s?00zrWw9JzDP5y;!`H;nfO%?V=4WC(KU%*{L!OqUoMe?2Ll}p$Ixnep4 zwVmn722LO!a%DadEo96{3@iYsIf4;nG^eUxjWXrShCge56>HlvIm3<7J>8kQ+$p;r z0EjkjhVGId8k8XWwadM3+gJ^yaDHJ};x(kx zjv4k_e-U+^DTcaZR0{l513Bz_S>r`X+5(J$5g)Ute1P5rz|ya%$gEUnWahg~nHo>Y zYma}^XH+|!Ngr;Ztf~n6RE;)?aCf(;TM3#$oO+(HG%)KK0Z<@CrZZ4oU}~4?OD7mB zr4k$;`{o!APWm!%FC5_ft^G?V4WbcXO+9JXq^XSE4#t%6(&Hifgmd;993jhPFbtxx z>l;*Ea0)HXqB7lsF`$`W(`2%NR2^QZI{(Wk1wHCG!&!_&pgY3vX9)nwiEqaW3v5;8 zLzoJ|4v9m=BVcD1yf={-ic0|HNuijrh3Fdcqz}*@vLQ*`^6RO^pKmC*UObe8x%5BO z0+J}W3~E?2=NZ7IiTx{)6#8;RuUvRMqwcWD*0%?Cb z?vc#YI(ul&Q?}kOo;X zUt5Kq;!7nS=mHj2jQ=Xhin!JB#E!kN9boWlK_5?&BON*exVw!{3vMlF4X7BCy}hGP z!m>k2Clul#JQO0q8n$Ak%X<--{PZSy-oiA7w*@+#Ho!gIrRH^0qp1;;qB}tJHeFSY z;y{(cps>4Cj-bo%F&;5MA*js}#-Ob1S2vUb;lpk#XKon2`+r3mpFLl`xB#efQE z(MdZWHXEN^z!yYc_s>vE$V-1K2ujy0Y4^ThQV5VFDXWZE)u`%Tm;U0va3{eag!vks z=lXq)Qyk6|F33(VmXPpx$iKd-rcJJ7ZJ^`3912h;mrIBO(SO#Fu-*>nc^YphLt`!{ zf@&N9Tzw+ZBi}6bS>+@F9K|V)(iN}tGL_au$l+CoiuR(jHo09sjY-9l7}n(GDk2BP z1&_@3**N+(OXApS*P?NxmNJ^kL~{tg%u9?W*F-way;rg-_d`09Qgvvpuz{`5$7GuZ z&;GW+oBHl)I;mKgv|nBDU(k znOLsM<&94wDnkI>>&MIFSrb$t7OpUKf{{44C%hJVsP7^6RHm^oR>QtV4r3=V??O#) zo$oc5Sr!0LVQJ{4=a8oZ5D~!ob-UEsiz~7#)`Dc^#)F?73oaZ<7ahz4m|33Dnl4q{ zMcpmhj&H_ZkO@rk(=%gH`lFU=N6nMjI0-fy444u+cB4Y4RYC{H8bi444wAA6%Qb(S zxdHa@m!=~iq--l_^IfF}wou8pgXD()n(!&-qd)qELYC~gSF0#=__gkVig>UX6qkD! zNL*vYR-3*7{cugiY1#QtLj}9()Qc#A$0DA^JGaAK%w1?ZsQ3cm;ejDG_saVQ`ygg# z)I>_dUHm=Tu4-$p+d}@?xT7OQwM)EKp=eZp9$h1**S@ywzs!rgbyaPW=q&K24DR9sWa_*R^eAog2Y{OP`^mU^kjEll(5< zRqlO$)s$WS#E~XSucFzS&xx#g;80m_WGhmv66B_XfCRIkRD{R*rCIyHI_@f-dTat3 zKu!b~VQyGK7HsZkM)Zg_S?KvM-JPs%n@3;hGj;Hi1OwRker@&ldq8{meKp zUey=C=m4;=7UE4SQ8|I{wO2~&L{oWE1Cg`^h)`zzvv8L*L}2|p+>$7N*C-A*?jF2l zg}^C2lMi*#0O$K3H@Dqs$_+sLDVW-a6YHxCjmX>=bYuW+?9RD$)eTNqNr{#nL3M~i zukWJLhTmSf=eT19;#xx4p2TAXsn%rab=&g_r&m4eKM>DqkAGNV*-ABfZ~Xcho_-t_p@ zkVGY}7Jt1Yq#=LwJo@}oduL#EhvdySphH(M$ijZUwd{vOv8R`>%T-{!--O_FGbtwe z@zu(sO`X$L4X}n<$;SX;0CyU597uM-ALo4Dw^jIfCR5le{=hEeE{>1U)S(iooSD9~ z=1&yK$w!Y#LV7& zd-m&Z`xzqxWeN51U1W#;&J=8sE!Ad}HDg6@RHs2ec3Dd&YH#fqqh<|bPtF9m#&iH1 zngeVo=AEwZM&CGQ&m;oE6|E4KU%Ej2zK_|sq}2MpUtjxeNo6<4b}?tNG+MS(0kbiz zUNm?OP}V7gEKYs(d2#)Fg&wY%^Y4(Yi1X=7w%vq5iXL8HTKndn-iY`~9@oEh*kfx4 z)Ed@)WzBek_xvPTHGrSwU?)F=sPGDRQ3$VkXDV?~Vfc;I)MW+-4oN{O^T7ZZMZjd%I_?@{S=hCbyw*sLK7ii<-G^$RsI1zd&)cfRE_~XaE6FzD@p>}0QOr#p zU^FDHR}u~Dg4Ol}Uq78{lV<2)JPrO>BbVkL5YkfUAl~l}+Pa(h1Q0nl^Y~e9VflN2 z=Jzl#Mrz`)X;Lmvec(hzPstGYPPfg)T%R!yvI#)z!r_1f5H-mSSwP}OSYs06wGr`= zS)=wSX3YkuCX|WPzU)$Cc2)aHbrH9z-bO||w3^lt;r80CpXqtV0a2P!(TFd5CF6aK zcy&ZsCaJ}ezr~WaTwzranu8VsEw6%mpd|ej%N7t0+Ugj;>SSer)^LE0%jo1x*Kd-H zr6N&_@;>=MeG)=~?8vM*sFGr#qXUl9hG zj*2?V5=c42su-dqpT@{_p5eb23M2!_K&k1K|06fZ_uqI#1F||px&9aITrDipUF0+( z4^8X4H~#xQadejPYFaPeOGRo7kNy2{iD+OD0vMgq)QI8;`$bn)rt8=_nucV(oU$-(^haK|fI z2{xuv-~QRB0D=?+whWzYI$16+B>v(O2SiPi2FzM|)+SXSZ8Lxu%b5|McKos$C=%b# znOk#HyW?G2LwWEoJ%bX#?9UfuEg1nkpXcaHptMB0#?HvOHoOqm502r8(x*Ay1{96! zL-@&I`6{W0)au-hl~%C;2H&wOP&n8pGoqH<_EP`P`Dqq$fFw@Uv^!gknPSD1?0a)T z3a@>0vfsG~HYD56xh2Tv3x_{}gnuaX7tvFyqAu>pN z3t>^QF}UP`9zhYm;(W(QeGCoC%GY)`=%dz10<~nl(9UkCorlAg5Q;0prcSs8tDwZp z=y>hF#^`%%visnxy(b{ARfinr(k4V9LY(ayq?}JG)3U`Tn*?766}Lt`mz=>PI42>bfGG3s!^J$xQH0~l#c zQAwT5bG%>@kHT zSZ&9peqSie?#0Rwlpr4a>yf}B1e*m!e?JoJs?m$MPkXX(wciQ$RHs_Riku=hqyo>% zr8RS50-RkS7)0<_F{l5H#uS~9h{(JzK10Y2G*qZw6d`&ur8i3Z9c-EUtk*nN4Z7<% zMmiyxV18Ymkb;5svht}sLPKl5eCuE?Q)H57+*P1BLsC9RB(AXHuX6=bMrbL8U0Q|i z!_;Wypzrb(1T`=|T;wR>w58fAgEIG+DtG&@qZSfU!NV6 z_YnD%Emr|C6rjY>oV=Vy5Sc%Ltd{Vf&lJ$lJpA*>g}P-A!4Xy7zY6YuKgFP&5}0QI zM!DO{_*91e{MoK2YptSBJ$PosA3VCkbgG1@z1RP{zQkkcA(EErh?4=Tls%F(qWks zIMfDN2=#wDiopx{KddJ_J9H2@{s#Ym?teNN;*bF7>LZc*|4#>Ai1_`7WdW=v^Zz6$ zfM|dY@U|XC{Ez2mq`moH;rzFUiu}J3j)xR*9#bjr;U8G+yA8*C;55noHKCxAr1zZ@ z(HsfGmVX|RLQK1SKR!WoYUg%a`FjbwwY3Ys0ZedD@(AtBGbw;PB| zn}ux>by7o3!qKSdAR&p1-*$Bz3N%K(^;bYhU>=Y+dq!++xyqi<nlb{)#-YguLhpq(u;K+I`Cr@5tEReX7HE1pG(wm|AL=bJ(l1SbhrE1pyoPJb(O90p$$hd zpqfIf_6_8_fNC0ey4*D6;y0=L3KkSO{uTW)_C$%kwew7Jaxx(QeXB4oqvMU?j?X)_ z>#1AD54v8GdLJvB{6I_fKGlXIKO+BAIgMUBCd{l0UOZzZhItd9F>A75iyztkr#o?0 zDPM{CSu%eqFOQ=JTAcr1jD2-nmD%_81r?-K5JV6Zq`M^qrBfOOq$DM!1f-Od5KvG+ zN~BYi?lO>Wq(MSLLb`eP1$1=2GxPrZYd((m-t(NZW9_xqKF?R&EY+yTmu!2>O)p4r zezQHXEvLee*xX5Dm@FS>DOlu*%O{zILJgtuc$;F=?tQQk(&)Ji zC##`84AgCmV4JKKyxV^Hw?#ykx4O`W1zr)&3Qeu0bR&>6sT1=zh9t%_D#XAg6n|%r7XA$Pu^T~!-dvTY zRrz!Mfx>f0-R-c;@)M1g^=SKU^~r=&jj>lXvyLOCTbvilQw(&mFfj`(`jfklJ!8j^ zQ9|pe19VBx7b)+3#@gogcD6=Gh1n3UypdjOmi#h}N2FV9-%H((sQKq9W^lh~U0~6` z+@p-ml^pca{kUnGPZ0SvvC+O~?q$`N_jglblDj>%Lc)F=Gmf_Q=`-V+n~btjo863p zOQ-TI`qg;-37IrpK%j1_ijcHz=KV%$n1cm>mH5|M8s?t};LLyB(8=JMkHW zl6;&N{<)};yD@BFEWE>R+ZIvWPuH2yhy@&TG`fZd9?WLVupKXkiSw>>L`bvC`k=#H zU%s+$NwTV{D)_#<>0G97qO8ZWuxieCdIsZn?-6D7f4)nXxjMF0Q>YQSg`RzC`-TET z|BtVwo%gYs%QdqCALD;Zr4&m^eg77H2nz-f3#=}F%*?MCOJ=8AhQOAJo*!V?@FFe$ z(n%@emd!aU_l&h3ErI==Wm5}seSuZkc=QriLp}-;r@Au1H7%x4?Wg4czKYQdwS^{4a7eC9#8Dtc3-fnkK)ff(P zovCFaAn?(dz05c4CHS&YWj)Bzxy5XT{&Da3;s#1I$^F6c+!ky;wT4e!nmy8;TvlR@ zBvda|i)=GW{Kt|R>2g6y@8Pj{{3DFO%zt^SztMUUE9zllU}4$D*MLcFdRF-crCYZ) zKGVdd&Tc##3lbKkZYIw^{2hG3!J*Ri4x=G~O-gsznwvVV_8DsN zi=xrho%ZiY!1blU^=q7X>Vx_U%FE=YpX*R;&B?WxaJf$Oi&AF5RSo&+rg>)F^@ZY5 zEV~yed3M>OKdh&kaZP~A^?5X@#dkZ4-IUYLMSJ+gR(BMouq?)iX8a%bPN$E=)!Q!T zCER#AcBiS|hIM9te`v{^R;ME;xJ2!BMG+;ZRcGDXzS{i|s`WDJ;i0b7tD9CZ=wqWx zNXXCYE~la#8rEBEYiyriwrJd$s))?bw42Lu`;0>sOZ5zKz!*r;#Do!zlkac%mKb%5 zD18)xY^{7XoK3IB3r}#PYDeoa+iPRalKXS?C50u)Ek!#^4f!Knf(&Yz8*rc1lVh6` z;W}zr8eJ9T(Qv(p$B7wJM2Mx!TCXt`6%{WpZ%2wekumGC`mE0WR!r6~^C3Sk5RK37Ts|WfGa*gmTeNMEB8nZjdfnF#0nVV#hbjJ9tLFG5!V1X^pt2DX;sxO(Bq!c#zC})P|3W&CT1W1K%~<-tg(;Y zTV$=Tr8Ni?!;>?I(5H1@aMLP3Kzyz+*fsjvPJwA|!J1Zn>rDHnd}BdntOR<~k1_kg zDyO2Qg|bkBA#gA1EZG+Ne3h$3jud?1JXev}O7V*3d+g%BxY`MQV&3Vqz;hqg&@&C zPF3{5j`QqpcQ1EVAu3 zC$Awca%11;4+)b}Fg~Uz>fizb=FxS0XHKQtF&D6!3w$De_@8FF^&?MXzG%Ik#N~|J zEzM^o&%>O?p76Z)2`is|rZ z`@r?K;PDW37~^cg9+a*xTW;p(;^Nv-3d9mhtF{(|^wSR`4m%mlh=+|H``5oCEgj~?$A(WJ5{aVofBlS{Sfzb|oUx{e zXv%G-l$tI}XDRsCmQ;qoFJ!>Vc459vmFU{#oy0Xf;$ROIMxp2dq~U8`GOiouus<=$0YS2H;rqiMZDF^ z>3;+u;SAp$zL)-PrK7eMZF5UHv#*Ud>d^bXOv8Uth~}02z~W5>IPijh-qp(Jp3)>3 z=4p}#;GLZ(PGP{Fh| z*V8A0ocD*vecaYPG-8zo;gY?9BE^4umVv`(*|N_{7vD3}>co!wLLIlju$Rv)ESkYG zAL9Ao$5qqfF(aVq%h!h}>GaY6!K7PNju$>oyARz35J*;bi#2ukz8x_)drZ6l(%+Ec z@pbqH!9|DSOGHKl+_P#*lgMEHrPT+AL)!TM-Zq@Oz;fWhxpQ4<2EYqA^YWf5 z5#pLr_5Q{C$e867^thxs=mgkaqhsNGn8;*Jf9FzTYgQum7q7TZ1fo@7gZw@2-_7g2 z`MvLUJY@cP6DimgN@(Ua@}~P$4k(D}6UI#c>kw^pJ!MRvCYf5&Cg{4d5*yct-7BG8 z4D|PJ!C=U3drmPy+|Rx11R_M;pi!M62^kjt@T@jEau*uUP<9vuc>1L^R9-Oc-wq#q z_m@*OqJ3&Wy1)|_=A?G$S;+h7OfMUnSHa3d*oMVElAc7o_xTk#rcLO#=J5OT zcmu|fCwH%@Uqd%+rw0n@1dUsnO`6GseDi${9H2`0@rgVD=PKO$ID`5ac5LsGenmha z?E1yZFt|5#WXF(QE8qJ-1KrvlMHIP>|Ff8T z0n@a*glx-<7D+L## z9kcWlZ~V(`NJ|h&r0aL!k&(Y!IPCUYG};*P#Dhwi`Ox2`jnk+vO17{4^OCN=^^0SOjSNY_m9bj5NEnqMROqT|H1T+I)~Nkc2$XT%#xdk}l-L?gd1cP8U9oG!7^0 z3p`;OKPI@Ph(=>rU^NU2s5*vscy|Ar;XO2EB@RAk&tlP6jQrf1ywlpPwZy|+MApQY z4Zr`RLxK;0LuTa`vRG`~*0d`<^u)fbVD44Y{8noYKDuRqv;H{9A@G0My+c2Ay%WW4 z{1iT(+RMjJ7!3)JBy;Y~1&0E7{$N+ePm@pNQxAg_6bn?`cF0RAkM5HE zuYac^{7!*c@WojKABd*6r(`a(ZM=M(dR;NGc96$`;oBhM6H{Z&(7^tBqb*)Dqix~$ z#ut^&4z#qwdi+FR)_gqf;7-J-5mwhuNl#9w1by%?@~;TUdMzADBOe<=)A!C0YY?$@ zPa3Cju*9B$lQT@99S2cGM0!2&k%G8EbrL0}zrvU169wh*uOdY5?mZQ2RVaBDtfUwp zsFWrvEnQz%_lo2i`HeJi8}oa|+0cZEpPmR0qD{Va|FVWlwt^6$1-` zM@63WT9}yi%#E}ON;Wpdc!dy&5){O>7k_*{@m!(#wn0A$CMITv4XyfB9!lKS)n|lW z?ChS(rkf*1nj>>E2qTZE@)wDx>K`)}*@?1!p!iT^*iX|xq@bX1>+Gd4^`f}!@H`b2 z+R&#@ug99eCA)UVrfTW(UGC+=)r+SQtk|K0=S~`m65i%}9dYOBoq>0Ap%zxOw37-S zB{UlQMQ*aQymjcZ4ed~%=HTc+jSoD1PnwB*z#Pj`?KlFv)_~`)r-juzTd6zxq>~45 zKaZFEfvKpl!Aze2c5z+`zD1ZeSC?Fi8qHcLDz%@qt~;$-Y5eo|1P~Av($Xps6`=fPIGgR&HB4UF z2HHUbH(Q!8H$?RY!GvTjEt#EOM?{=E`le^0p|v$Nb(Dj;rmU%m#^cnbY)40X{WNBO zaa92i0f8;84zKzZ^!DeC4WAhUa!dkt3#T7Q$%uKgJ2^Rx`@K#`m_}>$RW{XS{>!p9 zJSZRk(>Gb%X6)PScy$_W@07rh zIHjL+^57*G5yG^ThVZe@?RlnBEF9U`*ob9hG$y{f{|zpJM!EL! zrw1T%&JYnvOils>lIM{Oj@EBYxp3y98PVCZVm%&$(Mk>IJpCR~XHgKfti4YZvlTvK z>#01Vdv;{bh{=(uwgjQQ4N9#B4O3J4$S7cn5=k7dcUyL)tJ*P5)iVFx7QX5peSUZ7 zIGy$-#ITF2>s0}PDUEI~1*1cOIgmH511u{D^k{{9=#hi(!7^TfzUm7Xk(s= zCz7FUt{ER6KmOE`7X9F45tA1$Uw&U*{V3aziHYe+V-rO4Hk`6l?eZ-s-={TNeYNsj zB(1N#AvmXkFhV_uCCKHU%89`;cRt37u2o{ENK0VH1k=C0dU|>{-)JY1IR5w=z{0Fq z5C~84MeLaE&FtH6^YShS+Z{tJo&Yns7$wN!8h?IZVQ8?v-aq?92;zR*(xne57ZBI@u6Ud~79V)!oT{$> zUqC<=x+OJ=~PNA{Vd=W!h5d~C;e0(ntQ-I}~#xpS1gVUt@$kZ>`yM~6y6mVMd zYHVWCENI0kbKKuu*S~XT>ToCi45|m`c=;$Ezf!>?7c6t#zHekiJ%~t#p#KAAa$#ep zr>6}pEr-e?Ek{1cu$1SSv{Aqb=@I=sE?TpuR}o0DS@ybFc@Vs59S;#Qs`bGEwuNEG z7F2FH_MDaj8-otR_I7sBLhcohSd*YLWiWaIi?9{vJg~ztta`$^Moo;IV7E&^#h8D| zd8B;H9 z1?BuPG;AbXoj!1ej$}D-2C&Psr%zx1zd1uhXaEt*vnGO5r!MZ;LT_$7E=wcdrc;5I z051Kw`{X>Aq+tLd6EsE=_WMnN)yBG;rJT~tzfhK-LZ8+RBi@>tn(wN7$=$Bp8>vE8 zv}QfoER{R#X~g{Z8S`_xTjNEzP=dt3O{ck^(=#*QFj-w(JY`ykHy*boGu>P2z@mPU zo&A|5ZDQ%en3xO2M#LjOl(TJlnD37Qw^%4Y5aQ>aIq5Z9sl+%6vujFaTGR4QSPG`yO&a$ zc~5qX*wYqmDx#M0rS`6_RXA?d47Js@wQdV4A3X9KZnN+G@Ktt!@{@9vS{OMcOg!q4 z)=#yxv~-@+q%}pJ94kg)67F8bBNJ%V3Y3(Q2?!1rvY#Q?e11nH@);p5cNpE8m81{F zS+uJz8zJZ8#?>X0*5cIF)s0(XpFDX&)e;3>m;34gQ(X;x(*UpSWT54q>i686{(7}O z`KDd|*@jPc4E-O#F!>ldZV2`01zEJA3QnLx;dihy%)V41dBihE`N&QJA3ZjEeIehD|QyjJ=t2HXF`ngXnDib-`+W~nUa+?2POf+>3(2@ zv2ZMC^&L^@!`K#iE}I#|V+4Cqc~?EYD1*rbk4d$EyZiyyX5@}xT?+tiO84V77P-*e zf^(Rz@NH;oduusZl5f^S#%+G9(rvfSjAQ3}jg@K+upB@dIfH{17Z*d8GC)B5y-4z4 zsLTmcIESwmrwZ#oZb^sx{`N4R{S54~P~Ul*H2Lla5X@?Xp5Pg(yj;J1s?Qw^VWFfl zDl$@vnG56svV;4=gt>3uo^HqVSQ(j^$Oj-ZXh_?qfUJ}W`5a^ojEzH6A_Sb?LH0>g zsQ_NF=_OY~ef=5JlMW6J0X2}CEmqdI{a@G3c zy-~}0x!9c!^b)t#(Cu|ODF_D?l@*YoN8^Hmf(X4af?hl_?om(w8uFaV3_`0Uhf(7d zr=`nUSX+&HMDTVlrK;2K0lXjNnXu?+QbIy;vS}Y1U1ZTiEdmd{&*;C6ngGmLfk~V2 zhPpYea_N1GIU#SJK2iZk1x-qq&Ib7TJT8r%H#%|r4%xoG5;1)CjGWOiF)~{(Ei7n5 zV`Ai9EVRaZDpbO~AWH6IA90SwHzvu1*R}NB63sDeAUu3nJCR7GeV=i~Z3|Hd<(N1) z`2_`g3-0?2ogr!vtmmwzOWgPOK&ovLELK6rOf1z;;@p3mbA(;+q>DkVTbqR(`mqzz? zw`*EH`mzfO3KH_^D9p{xX?@p`-zZ6fXA6x3Ap%6vUbr#rPNiYm-HzlJFJ9PX`B>71 zMn!49(Z0I$eLO8gC5^(RH1v_ed zr5^3zFmV=M06gqC@%(0;Y`ocZ^7T>^{F3t?BMbL20Uksyr&innf+=<_+ub+T?iM()f zacIdC9S=}WJ_K)uo7n=klZ`LA%<5WTu>xRnIoICC2j=J7KNeR|2+7FESd8f&SGv7D z(NuHudP_8~@&=7qksmcRwRn=B6%gGPSWOOh0Y7m zFn>GVXUEC={F28k97CbyU{e&&KJ!!?0!Bh@OP&>^+OQxOBojV{;o$Yz^X08D8Bq$x2>7FW{ z#V|ZXWs5afEG9ahqY6G>3M@1M|9GY3=H&(Y`@d_&FvMoL=FOhozUKqDHcK%9ZPPR4 zCROL{3K#V$wbDRo{5NGkK9UII0ccoWU$2A;rToDvvJa~F=#B`n>fILYY9nax!Zjjo zNH7u@GHdO(gY#MEziUw2qCznW9;+b%z)G;%DIb3&1%*YVgZJEUv`LN z(SojgkOmX4JigZZ4@H+~b~%)*pD70waLvD=_75Q%tD|{sAqq(JyrcGFZ)$f^TQ3(zIv_|MOlIW0q!mFam0u>REf^XJLQ<#`rggGqOW zzY|eJmazX){bCU^B0=o5#;Lo2IAAM~A>w`;0-?bDTRp0ztelXL@cU}vMVQA|>FN+? zs)3jQtal6{iTC=?s#5 zdB`&GJ^!-zZv=tsyEz=hEk*k02A0{{SJrue7RKWi=c2_H#}#kPzq%> z6PU%E6i6N;Om}x{)d1JX*ti2HQ#DJ&9&Fx@iDd|+V*rzZzzCkhC9nTq(&*vCx!bz^ zBoBGN6j@V7az#c)!s>BxaRDwRnK}J{BE=nY`oWf;kEnfx%8LJsZ~E(_d3W(6xxm?z zNUjA!f&6L6~C?e)+3>e||5uvLzZ8^yNYrZj#MDX0$hhzN{-WKghG-)OsTE=|CWzzbl5 zNO^_-FLsCg5J)-ULmGJ|Y(|ae{@a4qJ{RyHY;znIwAsy|vYA5b)^_gfRk`ZrTzwM5yl-B{FPe`7UVA;*)W1|0tQ05eBsXMp3J{;`l7Y{}VLNQzt?nCmf!IuDiMf%b86S~wuydI{0 z1j<1vj)(_e-J(Y_#us=dzZ8t0^|iZ4FHS% zw;dhDze|^@+uPrv4&73L0<1zL65O)wKYwk_86T?PvjF(Wz!7Pyy|IYu%BbN`&7d;Y z&e26dEqrHF7aFWO59Bkj zA#IiJ?%=a;2S-Jm{vm0Hg@%TPg^B(ijIwnqZx}WC;nN^j(VfK)cmh@dS}sE%297w_ z|6-qcEC(*;QVR;kS|ZrW%F91JA(1$UG>?iqJ3FVQOpwGpLg%pO_D9Bt_eWhfYJzuT zPaQ--G{nPq{~Q6Kj)#8DvuDp>gzW ziAx^kLoH!TS`V7)0wCo6+j@70ya0ZB`}jOVb|yV<{wJ?HIY#(U2w298 z%WysEAejD}vZZ>!f>V%=H8p*Ge2@6 zMEs9ENUHkh%zZdluzK)DPBUn7nOj4H)`Z9mPPlV5T zZu2Wh2>pTxFiLgxAF=Q;0Xqi=3u5sO)J+EOpq=-K#h|a9LmlZ4Bd1XR3d9k|l9Y&# zP<2jssv;$rhJ?hYSFbMqS_*WVMKQ-wTi_`$r#((dz}w>yQli&YA`4bz36U7=ir2$~ zZXa~(20mgdpc!aOh>1bH!e!cN0^tju4mxqC>cgb{Jx_+=98{}MJxC;Pg7moSqKB>L#{?0# z$585yuZPBb_7a0e(|Q7C5fWc*`%o5G`2f6Qfl91BNd{Ui=Xop}t!c-gS+%h6CnYY5 zDVzNRVc@a-x!ItGBJ8y9w&ID~(sFW7f`TApi0~fu;_zWJZk0K*K@Sv;q_(yeU~N%R z5lqPY9l*n%x!e#DY9@e)9C3Tc5eXgJ_oHqqDChhRvvOoAvuG5TK7yD}RQOM4vlVrg|ST%kg@0zJ}5<3F}JdGx3c}0M@=rg&cu1-gQNkc=j^p#s;4Il*%v!vNbp;LAQV zH1sFRIQ(%XsIDBK*;-N`5LAiL_6#9@ST>2WKtSWf*YL0`u!dJz{9wf*= z-Bt2>nu?K;5gGIvSy@}_>+5T4MN~*dFfcKfR#&Oe??49tHl2ioL{qc>(J}N`Xctd+ zq>L9&rG!&a;}iZCtz5U2OifMg>^KjK41=?_cmYXCRG;DlgM;yeBb9#Z(ktoOJVCz* z0*p*biJ+p=(*EAw&8@9=I+@MmXlM@{9l!MTl@u2<=~V2%K2Sex`29?W#XcQ2#$}P3 zW~l5^%+!G$%6w>?#(06x&Sbda>VXd)lzPumJ?jtrw{c>89NCwGU07RN+uPf-ORhON z-7BRJMhO&LqK?;mAFkdK~z(&TG z0uVJZ>r@Otzs_5@4M=T1X+3&yr>3SXFc@U}N?aUmSINNVForbC{Gww-mnWM(1rm$& zc$@>}fRv;pKo2CTa@G%g5+Nd;v;<5WaA5D=zSY~yPP&6p92g$n12o{$^71s%Wtt;H z(?(6E{i%=nmErv$2{P(bL}#DS#Q{hb^7SFEO)dD@!}t^!-Wx3G`uH)~b$iXug@PEg z8F0)t>6FV?$qqwSbogNsI>7u@tw?D+iq$hz-XnF1M@w4-qnXg2hCdC< zS~3LsB^2^AU%#^3PRjDSOK~55on?@>uG%lH0;>vJ+-+rbXk&@q*f@f|haj4cwfN&P z-3iz-NZ@I}rXu^^or&hc!lg_h^E7-Nd9uQziRpSKsw@* z2}t(5TbnOk2)e-kB74HSvQh}_@Rt_hFwsOn)VsLc33K+ny^%q(^%RLR_jDy`tmKWo z%d?)_@=FK_3Dp+Mrre0B%Wa9`2`)Rc_2Kie!)GEDKGZM_IWm4=I6g82!c}&Y){8(Z zLs9hbA;RYMA9|Vt7f0YjT?f@2H#hf0rChR%q(V+*@EhNRsL;7ZvLUQbJ{u+d{r$a; z4<4YQqj$&g?Dc%_euaW zLbM01<~a@{Y~-F`PEAcoLd5+GARleY0yr4(*Q&GxR3E64PQspylaGweOd9Z8E2Idm z-%#4+ledozTTuNrNhr>dOGb*T$(fz&8IzxpVfHqTg|f^u4bld1m+?BUv42Go+0*?k z?x%l(704IUy}2|1R)E7740S?SnusPL1q|Nfv^~R6w&mEZ&f~p`214F# zZ`0V!%#56zoSuqKH9X|i!=NFu=KCVT<@g2iDq4XGS{Dr;m7Ht~TyrB{ZDP+=H8$S0 zTG(JKcO|%A;P%1wbxs_4+I*353)zfkid+Yd_ni}J_ zKsRRPd*Zvrl`;HzX5Yqdtu#b{Pz|Vg3gA6&(jEINT1xtt#`Gd(uqY9JRaI4>)@aK| zWFmtDaOc-8kw`YI0~mtdg9aKpJvp0fOr4#{!u0D~=es$^R#3Z=K6odwhMyLWG%jp3 zv5o9aG}sZa|5heg6KUZvau42O?Rz!sCEvQfK*)kr_{i&n{3<(osz*0WT zp7;R#+s^Lpk?`%e_)8lM>M7_+1#Gi_*R`h@o14tJ-~F&GKt=_l!LDA(zPK!L@kM0K zIvYlD<0d#poa{Z@Gsu}5Suy~7#Yp?=6-_c(b6K%LrNzlc`xKmA>UKKNUm2S zOEz6rd{layxwplO%qH8<#M~DDR%_VYq8JmE#mB$=W^l~MZrSecx5RBOSpZUGWMm)< zt#n>z-qm0r`ROCS$smzGoiQMOYc9NNst&}fJ`{64YS(2GUC-R!Zw5x9qbdiggH{Yn6&W*pFx;OFNb>{s;{BV3&Q5?`LNyP~KS8>^G)r%$okAT38r zInLgglrj%aJO8U-MTkQUJfSB`J2w2erJ;$<#ZhwYgW&_e z#)UR-F`972%3vwyT-oXPM$a!&r-#u1&tt}MGP<-{8JD?Y9KXVX@>4;J573*Lnc0r% zvGv#YetdE5kQu!&> zGLwmsZN@}Arr~6K;374(9IZ$_Rnw>X+Zw4QlCIqgj9tBvn=~mg8XTP;+M0pgYWCLg z8_d!ytlZy=`fDGWWvU3??(PsBvHKjS&z+kZ9~bRG1v=_L1B_m*2Sthk8FYQW4_8(u zBv4-XXyWDNwQ+xOdSo=mZT^~lvkjM$ZB*bSStJR}1I(+_+KLqE7_BZluxhDi!vHjT z=%RY%2XA&`qx5FkedmRuAG>^4?h4NH92N$^S3(R~G0QUlJuCg<^MQqYjO6pHqje9} zvo?ljFI-@%on_!fmQM;~g;v8*wPluavW`=wDbzj^!)DPdjUDx1gC}e1v5^% zMn2WA54y-nRQz7vp6rc^@b_WwW6?bWB1liSd@CI#m_mRK2;q8eVeXHmr9-SaKV0b! z{ldRue=gN;I$iFMg*Dh7lYd3W}QUZnf>CP7P=n3=L^txJs~1 zxTdnpr+ML>39wYckwV=WGC$%2CpipL6(%pbQ5pXk}q|AKnIaSWNxSF}xB0 zA`fo3Fx1!YfI5vn4CCaYgYA9Np~0(TQ-$dqp{n7NW`fG%+iOYrGgqh;Pa0whDNmNH zVMSmHO|7fbCM;jCtZeRbqblGI`z%0M;NWKE%x}hXlZfYLk2*(k2a5{YpVS( zv{!#hNhlqhUnot#;g-V3rD$*IKV##ybwRf0W`>pjX~8KT#dS}&n`Xk1bv0Hx?Jln% zl!|X$i*%alH&_vlyqm79tV)w|dG6e%9FcKULDtoN=S&?Exk`nf_ykGX{3-GO3~#XO zO_n1md6AFo&9uI{4#XoGF6l7+1}jz@QEDe41Y(}&;tsG@VyL7CeSI?~AMREx&s zzOy9TLRf}3f^Npdrt;w@^O0l&eAqV3#!wIB4)W_H7-Xr{R*I;ba$9}YY{A~AF!|n~ zt3`il&1)zCW6Ny+HlY9Ciqt=Z#TQo!Y$ocjxc0TuKrhMk%s{#G&08alksNkWA0bY9 zoj`){!n-E>j8H`;^mFFLMcFP-%9Y58Y)fpwz``{56Xlc}7+3?9?s1kKSMGn0$hijG z|Dc-W24+=eCSysw!h;7T(#vGJCGjC^!JDujtrq7&jaGvSAup+)(<=qBnHtd|GRhwY zm(Z|6O@7csJ8FHQAqfE56wt-nc$h*{Wo(SniyfIZnuGM6ONn*_l+Fr?+u!*PVHSx# zr_;T>U$W?HB;kLWDzl#EnM?Uh;6}XmVKW_Tn8>aE4R=^%GKOJ|YNf2o?uy({cE~3Z z)Li_64i-hSUw(QKG^Sod{(N>*AvxE8|AQxl#uOG7a(Wsz1vFINCrC+2r?_!!)EOAB z;d0wWi9^ElI)SX@V5f$K-XTd~xdhOV)S!a2Fu9)-Bu~_g_jWd{OR^NCr7_hP#2xFi6U%7#9K9wOgFemLE|bd@A9yb+kUET)INP5*#eXg;H%qzCr)r@8 z+f)w?-Y;GSnY;n(t!NRSFH#oIuvrL$p#!U1w<7MNg!sja_`1QBX2^^VeK`<5Luf$C zK@iyb$Smas;y)1jo*JqKpgRE50L_B_!#pc$y8^=YE@3l7b4~1hx2a|A)$p5k_>_0m zl80YpeB-f>J#E775Y;H98&`Z|8eO^$b!w2Ca!#f5B-$GqP3N2Uh71g|F$Z+k68q+s1Iq8b2GNz zZ~+7sqXr@+2$0`>S&%HvD6YDTiuzk*<;i-<1wFL9yxhtc7j&XTfs1M%a8xgltbI3% z++gD?Zgh+>NzO@Kco~^hl6NiigUQ!(78I0a)@f5IpHqc~9bV6TIoUN@k^W`qC0^K% zmWn(-H^X<;huxGY{Yw#N4;JHLZoS<0Oabjz16rF={oQ347)55J(cd!?g4!#}5b!7v z@Uyd~xz0upXQoc64)Ayb^c;FGI>FxZI3|JM=$`If{Sf(^7C;Pb9i$vOU6V9RH}Lp zHn^bq>yQO?>ra6eQ-Zl_HA)v?zotw zvDfP~MV=?BEFv#1H;|Jj?TIbTCWh({rz(@Rr|>-`PQ@_XN)w3`DYq#^Pt00v*t0<2 z^%y^DOdV2!@zJba<9By9epr>S5(3zO#%>o(xd6`tT)QYVh`;~2YnsG(3qu1OV?XFq zc065GgmBa@TuA?H=tDHgo)9a+(b7&FL!pvBc8>ljaW<}@m+0h_ZkN0;#qxLVNDtS+ z*z8rucUe}|p#)o9br^qDuX+Q*ym}`;cfjlo+`uLW5CS;4mtzV>pg@Nq`GYnYddQ(* zh~fmYV&P2J#%PV3n%IGDhTQ9uCbYip#Hk$7EWnb$ zX)Qa7!)`G8&9AZbn_u9(1-o;pVJ2)w{>{Bw&6U{@;sc)Y64+!g+12(ey0uf!!owYA zUkvzSMdX5b7$kTgLx?B!kHM;9Ft>EV#KW^1D1vq-QeG0lrVpyHg9abU_;1Bw?9Nk> zFXNw;>5~i$4cp$J1-@deYbkf-wy^jVn009eTdWR3SMc30xtd0?VjLgN#;ZQo&x@lJ zp<#c?qQ&=x!#K)aBhR6G^W2tL9Uk(uK864{hLrw5BI;AgpSpBeP;d_liCffzb?@{`mVZR%2Dgaho# z-1UL(9P*4(0e1C+{Ryn$#F-8afqXAd`%`;3sc~|(d_C8M!%jubKEuO2u`s`6@T4JB z%M&YhC`ISdVJ}Ad`u%g`Zw3H?j^brGpOli4n(oVI*i3;^Y}X7?Ry!T04r)>4Os*wH zSQIgbQ5n1)5c1Glm=uH=l~#~b@VgvTmhzKc1_p4um7V8`S4y&3wWPG+-tKS*w}ZUS zx1_+iZN_j#_xU&X8Ujx>ot&0^`nvf}o^|7?Rjadd26wgzzT-6wOg%3Uyh!syVyoBC z4;iYI{l~}0L4g}8WCyw{z z)7DogT3A)*?{6H8bB_Cb=8A2^aHwz1KP!CF@IZaT8pO`S@NNA|9&K=AR&{;tZs$|~ zc_xmQ`ImIqCVAHb6}(P(kr?>P7=)oeFtS>e39xB-tdpul*xJG*gLHz(_7lgCpB%+f zL=F#pfn&0e0}lW;cWM|V1fQ-sC20yDA?gHS0`6Y{HW)7WyuUDXAoju4L3Z=u@~`pq zh(jJ&e)3d(M4m?q9=n@*SV6khT2OO+t!vyjcI0woji=Z*dI#BB#?FBiv1`_@F5qHV<*UTbxx)E>ek?p8zo?WsOUN44u$M;sug$rY!+@kpQH) z^E?;Ky8bNzMT*es&tSIi-4J4Bw(zDf)})yj6`U~_du$Y&!r@K)WM0VoM4olvR{xtg z8g?gsR5FP^p`kwh{c4=8O@lz>f$4_<$eJE!Z7GLq^nk8U3P%eern}*qIE8P371bXN z1AX=jLora(Zu}Sz)|k#s^L-PY##vIVuU;WuX)|9j%ET` z<)Qc+lbNoDsZVTg%byEV zj0M>!=!wO8-Wgd~G(lwu9b0%W^FOTs8$FCyK9|`_PHST#!LVCB%H=t_bDGGD+Fi_! z$U6ZcA56v~1k**z!?s0i3+~HmS}xyf>j~zuZ*X4`+KL=MVDR+Ap#2V=Hvv3-%nL$p z(b@#p+!C*>R+qxaH-X5>daEB_KY+Lb#sP8*3UG07K&p$pPmX8UB@}ru$BqWI4{FuO zi~$8|0T+5Ltgm#o9J%iOn(|1* z0A~cc10-eSj5v~5A<0-8+vn%%5e&k#%Z}b!^UW9Ka@t?)M3*P&SMMpTYH_?RkMm}E zkW^SgI+G;OnxJb{7|nDcPP9)*qkZjepytq!rMl+MDOd)G$2DN~C`R_<9gy=PS91A7 z8s2;u8-o(|CECif3~FUCngBEd^zNWaNPv9-niZzrYsjwsrhxfODol)nCsa#C>t0UfUX;S7=&BA zxP~<~H4v<&krevxi9WWGn7ICA+`iJNA^R@ht1I;bf!{M=fhyw*v&=3AflCT;-g{0x{?@!V14g4ZZ3qUg=#mwpYjfyDFy9fGcl!v_7 z^v3|~evXELp{JRNU!@%#uk4z>di*WEaWA%H_+6raz(p(hp1>zV@@l+-8b-?|e$PYN zQXAN3KRv}Io-Ma=uva7_PTj2eZY<_xaIL!=;l-{{0{IMXy!6~@gLx^N-7WhP;;QHo zyZX$_KWA&NC21hF^gah#`g2Uw)E|%JKBLEM9r5#!O>KkhPK9Jv(zGf0ajIG+N7E7% ze@C)<(y3KOO+KgC6UOqS=K!4kZKRV%p zYW|~Z7wT{Ku3l-sw69C9I-sz-^yIW*L3MociHy4L+zTk0YE)32mA`~|NU{3Tj6su~)qu>IBy*dd5q zND!u!Ai`nr?|`)S<8?zy%}2q=OD7~Bc?uy%J<7@3XzXbzcS=%)ce8I8ze-l2w_Ua+ z6WCqfiD~G+!B}d$SSrz`jYm}I^sX;yq)vCxQLHjBvEj#SLjt;b{n}gyd)K_qEyXa+ ztw&b5?m{8kS9tlirLJEm0~y97sxYxuO`Ipq#6TWGL+Lo}VZ~w53k{BJL6M=J*fw@0Qc zBa4^H)luRD$wph=wpD-ic=MU)9pS_p`foToP?`z=5TFAUea*>^kl$lj1WL_kDhK!KC z>#}9fhFSLBD}*9jMwA`d+~?}E`h0)i`*%O?e|tP~z22{J&htFaInVRzg}BzkGnLt* zG`ZAz9v`BuLph9m)An6v4yv!3+$h(0u_bfh`{t_Q{-ExV!`Jre*Hsp~o9#GKh^sw^ zXKQF*inHmp-NShH<35nHl?i?1lkf|6Pe5M1-N^;iI>zcSK0eYmHkZN0|Bch0=-3tu z&Y8$yi?5XDVxOWiPQFOahF0|8`+15a*WT@rkLP1z?JVsqw4MhDgvNY!wfxTiwW-(k z=3a@8LG6Q^U!Pr|`55@DqpYv9edXyhYQd_nA}f9h!)_&?mOo~``F`EalBVD6N7Ptu zT=@FQna#}Szrq7yP#mhGz2%PqJQ441vzuOtoB6v_lNtF5R8JzCH)hK__$)ro)>(E<8+UWa3g^ z_4t<(fiq&+=NQh~8(3`Q8)cnm*p_)~9=@996+ zmPF`Hyfu4n^>sL}OGQ%B!|vOg=GM8|@`CpxT<3Nf=FcB|A9AE?Ax`b`R-bUTSQ;|P zoPJ}(9HelEjb4>aoGUw+2f^Ojy14LJU(S5xT%HfvV^Xoj&(}T`fA=Wm85};)Ytqzv zy*BoEN#e#Wf`baKKVrl%{8W+x*5=&5oLE0pQnxz+!cRRD3nuN0D8>bPQ0MRAlz%a? z?!p=cEJQ{i;(Kc~a%_${ax^ARWzXG*=g07f>c-01KE^bqkIz!utJC zue!reJC)u1fp$9SpSmQ5WkmxT0WIP;k|>tH1E(*c=_nRJ{-;rXkl zD$1?x-Hgn>&v7NjB=7M&c-ohB6nYPK(n!!^Qu0? zl#q0U5`Tzo88v_P-;r@)xy8+JsGTd(wOQ-X0 zO*aKG3-)c*gOY-^x=Z6>79+-ix>}1f?00*{9W(-eaTInJ3DFXVHX>*Z$g9y1<3n9u ziW(I11SmE_=Yzi$PCAsOwDZ3wG z6@rw$bK-8Xij5FP^@DsF@^3GBs|{Ki;$;M>DQQ#874ovFiFD+79Oz8gY8h7=j=G)S ztXUR~=1tU}*S@4Y?B=2-m#R3hqiU~A<}}tfRgDfJ-Pt<5kxssT z$1HGddUtsz0IxagSQ`2`gRQ~5D7wQ5meNH4S_{(gJ?G}j<*TUy1hRJL~R_`Pd@YpU5Yu$ptK7$$H_c) zc89T{ckOn~5z^JAtcv6DFM{pwMC zM}r7KWkvd8?u^4PpPUkg-G8L#PpM?>9s7E#@~rlackZTfMgwaBqaAzVY`?G3UI@8+ z{4iKi;jv zxN`7i7BTKj9kHE_-`+(fh@X&p#PakEqT{uYsN3j=aqhIU2|SvwhX&b~7BSu@`R@32 zy#CVJd{?-(yNvo;N$aT>-!45o*mP}Wx+y|W)$w%M`fFwX)Qc!f@z8Z~Cr3R=N%3kc z8t-4+U#qtY!O*iW12?gtp`iRd0%#DB?0^Pl=|S8!8o|d#*s6KJNs791QwnmMDkkB4 z3^$VQZ?;@`MK*$4azDw!jiY#dG+@@$UrFrK*M9mKHU*0tR-`-AGfiE3ra70oFQs;+ zc4i8f)0s|O6LjneZybJYcUUWr@6_4Ta-v6Ti^%h7RZAeRcZ6_e=ku(K?D^)eVE(A-{LAc~su8SzEzA2fW&c*9kYq_GWUUqmvH<(gUer>7 zmM&1Q$SeDN#=iIhHoP+ZCQq!_(3nlD-J_wXNTS=!oLMy4GRE~n(BY7=L-@C%d#-iX4Wzuh+Ih~JH!yM_}?L5ew#^{dm?4!hYM&Azn;7ittjj}axnrjwT=IQpZ zvvvBG&$p74>@ho&fj+TYs`pjbQ#C;|`mI^@cy5p6#D|*)o#Y)3pI7EfM-HcBOBh}| zj2wJ-%~X@i&u;qL!adgzV+bZCVgalB5XMp2?R@S#wNB zYiOJq-V`2M8!4;fy@}Uxw!>lk>ty*@x1E{!R%q&0|6$gky5T=o?=L*E0BJbmN){HD zUQ$KSg>hUQiiAR+>({Y5B>&+KbGhO}2)EkiX~#71f;{@Es-KD*MNdh1NFD}eP$hF0 z+7HbaZ`uhxS7H0IG3lFq;=S+(&+W*(W$h|)o#`Qcxe<}zd$niR94(cYuGJQ0EIn2w z9tq9U{ka>qgWRq(syCYU?qKLRzO1Tc{nq1g;Fx!^$?aA4Llm|E=MNn6`&+o?nPd?I zF~A2{cV#7XWL>=Xb{@1j(*BL3vhp6Fr0}^i=$+F$j5n2dry5RG+znavVVgkm=B6ID zzj|zTq$qUxa7;G4oc+dfwa5zt4!)y-Cob8$Jy$>M?{}5s#tj=&M|E(M9)>}DD&&U_IdR$ zmHrH;qBt-_L+J&3^}BDH1&R&X={Qc#J4TcI;?1#-vyI_ab{ACLXo8$p=HVhG`FH4+ zF+QCHy9?eLO38nMW>C8MF$qK9m7$0jdP%UQIazu8?EwOosb~0?$E!tM){X7xxm_zm zy(Yf2jNL4)9pii1{L+acyJnURLp1zqb=a!^!n%3$?j>Yy>3{sZ6yk||3^Yq-P5o+? z#KF0I_m|1l(sD+#GDGi#Ji0ztJG)lv|v-t)AgV5dG;O)o)g3<}?7I4axir^!^!Ju`f$e zVfG$~=DQqJ1+AZq5*&Zb>g`!9M@4Qvy>D;!FKgT=hqcDbe1fJxWNu-bN?g_;N8Q@g z)cX#{uK9gE-Ad3ED62}!?e_?DWQ__U^Wp6KICH#*gJ+L)d@rwih6l4YhW^o9A@JtH z*eShnsr+*O-#?&x>Mx4W#nlz!1E{C30&$UloA+=$`AjuuDs`FY)zw^(K1|iO7pBl1q>AS$0d!;(d zMKirDuCuJas&FEWBsuUbrUp)Q5J}4>0c+jnv;%2sa3s*1T3uBIeT~;|+yK@!>KDTJ z+43jCIEI-iMhDgGxi;NTXf)@TE*+^Di!NE=DYm;mrI=rJ{I|{j%do@IwmS*CZC@U% zquxqYjN-iWZ(Dd?LhhpGkg}+F;)+U(<>QgLNWG8oTlm%Ml)s8^+X@*m$4ami=U*A2 ziEBsu(j}dcyPhY=a&vPNyLuIBhF;%$7qkzN^zTsz{OR#PhkJIeXD3oazIKSNnu~pGCQ$;iyWDG-7MXazc0Wj^ij&eGS6A+bn5li+Uy2|=T9;vdXsLNT;;z=LdR zYKka)k&vJO3>f7_Gu({4}$t ziPbWYjJgGr>JfI2CZGFAQ)dvVT@PYZk|4`t*rxNsn~?~=phkUs;cWY%C*N}mwqiM} z=UsDlk86AOYGS*(y1N&bBf7S-CYQ*RvAsZ0O9Ry~yi%Nzk&zH+QAodOfPT5D&oy?l zLG)gX27&0qDI9L&h->aP6HhPrBErcj#prnMKi$I? zn82S>RaK=GK+nBT@XsPq3n=KSZHdkeK*%mkGZ9jr&fwSLM>nWG=wP&~PZpPrm}I6- z(y4JnEO&xZ4fhRMRuK{C>icAvbLYvc6NBV=8UOn#P9APZdLL&fNb=s7=JA zWLI@Sm}Rek7jF6A>VP4kKl7;afFYuMECPRItcnk zQRog(vvggZl;kCoRK)YVMT1;*^5=&3q$7|*f(0c)(;TFgVB@twY(Z=UWFYC7$&d3= zjb5rdp|3!cN&2ZMtE-8vX>hwJZoch_i6FabVQBlFnKCE0m2IvwZ>AzqX@oB~ zNv79pao1Smk%Azu{oKN@gxD~pp1%uYKtP&L6dt+C_Ob180KV(^o1yaK z>>^x_oRs-r2kCDHSgT{j%0M2~<6CaF>;-v{3b6S~*mMHAH66bVcxm!pAne6RM%bi4 zD|&)}C8adQ@j?zbGUh42-|j$*(l`knvsqOf>gTxpdpnkIQjgHG%+l3<52K74(8LtA#>$pDFouWTp8EN&-0N`^Q~WRpgoIJ|HUa`$Kde}aO#xV9J|@U z=u6n?wsRf^p@A-d(B?Sv-)BLqgb;M$(+SB~GwFD;T#cw3u>ok zolQ~Yf$jqdC|EY+IXLeGbvxK)LqYQ>T7vvk?An>`5V6PteCtQ5bHFCPD?t8ODxGL3 zcK^9}_rG8DcV);QQ_>wjWmVJ9GpRE1p`C6ZS%Z-8I-YN}igF3Yu(qGChAD^)v)P2R z_jq`#JK|6lP-;zjI-)0uL%U=#O(yu60}DHQai`txh8b^nJ9N|B-n}Ws+dwoDdVz;W zImBiiO3(_5Ej|~?grq+(mxiv-AX^M{VH6)%xyu`7H(7TqS|54}4A0^>-1P<{9&C#N z$5njX<`QohF4~AF<*nganaWrdJ>G629o8#l!MT=6_}M<;z@Zv3Wa`6Y!(UrnHD=HW zGKeS?s!1ic3TD?p6Baobzh|rplb^*wAoahSoqMC0H7~iWuGPJ$6>ZVCGs1>Ace3qc z-sZ~Hws0tGJfcZAL}rdzc9iy1pqmxrJPvjXW!&6*p*(;$0QW>uXOTf80W55}ZmLh^TY#nMwi;sf^q?zWRVpG&7f2nbJDk`p9p#FSKy=!~H2QNGrYxx4GIW_b47qXLsQq>lQ3e$a+;y`hSv)i+g zf@Qz(e;DxK1k?w|c9BYNkx|JsMHG7D_Qg!M{eY25RiithJ1L6@lM+-j0V^4_n2g-+KS4z4_Ov1Tj8&PW zeW_9!bi855!q7jYiAAO#oD5+!2>T!Y2#$p4ARdKx`WZqoMTQ$Q%iVr!D8@Aa=`y={ z+vCA2F|DYxdrr(ZQwp*aot&JY44YHqwXBrmq{$F%V@NX6WG0Xrxk^E-{Ziu%$c*v$ z$!9|4C^#_aKqBb*2{ycm@Hmme#UJ^FXih@{czpqKSX&7U+M@MHfHfE=JJ1g5R3?w^ z)Bk|6eJ=P*fl~XwK8bH1{qDT%Gh!dC~STUTM*5omzRR{p+5iHQtF?_ z#%e*>4Q4Tb;$;O0SqFF@H@r@dGjUf%U}+lo->s#QYP#{tdXzKmYybYvwRN8=23Z`JXj`fFs+QRiKXp3r05o>!;?eHaqDyugs z1G)3gD<3c)WaZ_9!oubr88(o{zJ7|hrhW)*&ymbG8(z^<95=yG5ou$66O^|yK<@xO zCyjXm3dUQU6B~hw{nB4A6QMVckL&Sf8*mAav!RhuDm}C)Q!(FmgmQ3l^v~quxYN*d z>R(j2h1DinuJ~SaboiLN1PU!#6iJz)Wn;nY+NnfE;r;q z)u!Ev$nz>WLpAP|4R1aWxk1*Sybl!HXfc3muED?*i-TTJbz!*biV+>gg9_Kji-oP! z6%W6HR?j5U0x-f508m%le;F(CU~*2X8#@e*oHSr(0DcYadFHjrtQE5Y@BD(V*dc42d&r)U-UZsH5#JsMU>}E2%531BI!Je)4Eg z{vH0J^U0_=h-TH|2+Rgx2}Tp|X-jv;%y2p}-vNxU=V4XJw^^uaA)6)X!x%gcd}}^< zOUoVfsCA)uf2N6gen@0^z%ED)KuOc*BIXE2m~t`k6@;-d z1vke*0KnHQI|7eSiBWK__z3f4ILB|06FB1^8w{%3$P!s}bx5?BOf*Y_gFe zX?+m7B)-D9Em8ZBnCbOHax%Re2n5372RS!(%-*gwM_B{-;RC3HW~^4Z%q^Xx4=v9# zID=lwjQYJ8)!eD|QTrar0ciE`U63<<;X+-_l6qFn< z-b+PNIZ+d<6KrVGWh&!k1{q0RNVSlgedl`V=8er(%!jt_ZWB>0X5Vw$VL)|+jpCC{ znioL}^(yC$l_@>+GA1)cV!$IBlo1ZX&K zlb7J{Lx=gpk7=I1Sz>T`L9DCKQ2XtJwbjN`P`{ekOm><-KorvpY7J0zuUl^C>;827 zF?3u3D#{bS(kqM=uo!_}FT4Jj$vst3=98)~vbq4szB_ljBbr;(@!M_MS6^XJnioH| zj+&W6g(c^-_4jRUb&eiTF}ntWH93qYs}6pSqkT z!7%|eGR(8}5#8}uPA+>#*WJVqO+eK_O|NegE(JvfRi(=h6JGCUNlAGJE<6)K^Z7I< z{rT^G1htt)c>whEOtC0~OWHiMTbfaCmZBCP4Bi@w$GwauZ#rQ@&jEIxQI;N_eN1+e zt2~Jec?M%aR}9ZBy>)={_gCrp(Th%dz+7nq{sV#g-kvyheji5YN|AN{5PISvWQ^_ND+R$8(g9wSPkPp^7x76+;?UAh=*43g-3aR>WPk(S zh1zitl(=}mstjZ%ZTdhOB8pWXq4DxI(Zd(<@gk<(XWL#Hw?6}k5(A>+`zZ7!oiZF% zEbw4X9Dv4v+qr7-?sGnFTxqo$Rl`{Z}h>g-i0#HV|WAw zFcjAh!=dW^UiAyz?q*pQ$!8I*E<2_rCG-bNaXq||c2_#rXL4|6y0 zRn#?-Ks@mw6O6(Ved-3_6jB}Jr-{Pc5;Smuw5<&*ZIi?^z|Dt-1XbnO%QWI zJ*~^^m2!stdJ;szHgy=~F#Ja*Nj2k{LwH+rZb}SZ!H7?RG>Wn~N&5?HiXBXb&M;Hr%%M?%5 z3c^Q)-dT!TURflDq+Q!_hBuOgR?B1!T9}{8PUTfDdr#CG=G;!n)E>eZG){6C)L&M+ z{u^0<-;O-9AE{pDY`er95gB>R3|eB|pLjS5dqRHF zbPCVk4scjl9Lnn>bqC(NNhJnZ`!UBsTe$)DBl}#Sd$gQc}HIR)sSEf_WeL9_0!{6arkWs z4G*9{2>H?E=K3u?*sw2%dYjOf8|2ZRF!;iL3^A}YtGud<=H@TEkK;`(^bd1UH5qrs zJi0-cM+|tpph`WgCxh@^n&C{vY{r>%4&b9+_ES6?C zyn5&12NPjW5TNc7>v;bjjr?&1{WPz}T0INCYq1I<1Nbstb+&@|Z=LDNjR`0~j{e1? zZa>}wgAYa3-Y>be3M6a=(N9TO<56I;pKu7hlNY>K5t9yI{LtS&g?$q%hNP8_^Lo=a*o|F1@3bHcp^j(`>|dWa_+(W487}iMn0|;n#_W5pa*plfxb3WikaY`RkC;6Slrcxn#-qAO z;Q4--?Tl#_3Nq<9uA%PkvSG%r4*DH8Q$oH+$`2CVdGKg_KV*zx`k=)ExqyQ2oA!0ktTiWEbb1W<5zJ(}xWI#6oW7N@ zN==1`xHuwz>}f@z0_j87oqjjeLMhZ@Hi)ZWL2 z9nIgao}9=csVmubnewFr)qZR7efZtAwKWJl2BJ$yQ?ho~=ldUIkt8sE%-6dn{u5>y ztCz7FZ6Mg%FQX^#1H2|^0H1ZAq4>FlzzB@N)p@N|2uf?-r>@!0k&LurN5)*ypg3^E z0RspcL**cvWX`n6@vq17$#d;hA|M8zq;P>W8cFiwl0jsvnH3|i=1y(S0q z1JZz&Numa|$CKw4VUe{E+^=DPhLzGpR2(QoUo(AS7sc?qicD;5&LcI^wTB7O3I@>H_Yt7H;^M^;O6pqDkfX?uzfsP|+5Fq#!rK zx}!k)JaqMf{*7L>>z&P+yEEn;iBNL`s`Iz!ZwzBa6oJnI9k~<)_<9;#tb)2_b_UMF zmptL(p(Y*JF&PjqywoXQhYDtUP#A?rRSk8#U|*jYVmtgU7K%64DaL^%cS@^!V-1h| zz2F3i7X%6eC9i+BfCptnu=p7^);{Jl?REnwHuTP0yYUdguLgUnvfvlEDgh&I7|vhI zp?iE99Lyh&Q3WCkdLH)uJ-9t1aO^TNGOR2tiqgbPtNrq+*9w{lGg8WzN=D)ZtuH~u z0aI*0w)(CB9pWE#N5YtZy(r2>TL|U7D2cNKJ4aiDrp8Gl@ z_Z|Rvh|q=s8QaEHNPEzXU{i`OcwQ8$w3#GRlSN_#|Dr6m_EZCZ5@r>hz4DN{HuCv5 zPo>S-57|?L7*Ne$;w~L+K>6drz^KVD6E=;cSVX0e(sTK;`i*pO7?8DkY6_z$#V6Tw zcW{CRKse5s`^Ta+l&lA-hyI~`^~U*fO3y*Y&EGgUB)6mQ_-tebweb`a}{5RyaRN#>dWDA z^Fja_aMI;KC{VhtKuJdMWncfV5LQR%!Xb7EYM)5I&462l=o6%8MIx3Itb{5-ntc5kS)YK8C2(GL+7+S zieM8c{fqvNOHJm%^YZE$R_lrri6*^yBqz=*uSw&fJ%(Xvr zKiC}n60V-1a_kZLijgx4Fb>530jX+*B}hJiy3QqqH4=84#})nOiI1wbPAHHL~MVx5zrrvbS5PQ#fJg|X`pg1tIt)g)L`wn zz=Muetv}qFKcnn}2rOqrbTbv0U*2icAcV{5<4OqgCs~R^>p&BinDyTviITs5y$J#n zF8FQ;YSWQEPYL+Z&i|K>T;ppF5hL}^3b`Vo&Sqf-G9A$1_eZ|L1VRkp2-*mg5a&B@ zH<4s)tdSolB2_zmF&;GqmNp3W%TFo$?6IXFjY#2|YeRo8Hl7VkRSOIVc+i{T1zri- z92J~Pz~i!EH>ejgRrp`>Ls=X~Ej<`ec!tpzr1zTx7%ywx;zz%Rpw*xgqN4FMnUmn^ z;9>#M2D1(TBSLB@7WFF=Lf|Pwt@J+^=R0c}RBxB|*UAJecf0s{;LJddj-J=>=`WJ7 z*kM5pdnK5gF@+?56Zp811Aiq4{1(XCK*4FzC5<5|9ncS!c)}fYLr2MB|hmvb^ZO z0`mV%IT4Uj*ItfghxlD>2!S$|y?*^EJ-oSO_%9?LJAT(d#x0)D6dNuCWc-t4!u}%3 z1v);DMno4C+>rv{<>1$VGV`K7W@u=*T(f5dH?1rA8bgw$&O9B_vH$x`GunOj>m>xj zHL3IUXp9CN$)i)ILJ}49PALxNgVhy>`Y}`D{%?m1*p1}HO|bJM7l2u$cH+g6B)5i4+h30fi{XJ3 z!?IHKP#Gd@HzVsz!|cr{rWCipjL9(LxSg{pdFtj-0cdr9NjF2mvxj(xT>9jhArIAK zvgVIKev*bEx8ORgw1rND(h3%ePvB@|VeMXX<-(<_7cRZ4`zS8J%6Unc(<*o@Z@B%a z8JAhsi}|-~v?N|L56K+DP<`&GMq?mZB}c{lkbXVf39MgK#2yMJkzxZ#h_yq`iIxEC z0Eb#|kcLZc{)mEt0U8j7;7MkzmL0_BTK3GPT?ku?&5~LJAg=zwNkBTXV>S4Z)A=>I8SFn?(G7eC@%K*pzm9 zEfyk9i_Wd*9)ZoO{~1gyaj$ak+pBze3|C^zB6-v{pNru$ z@A{TQDvD%9g6^hlHjmn#tH->lFaK`2Llgz3v%~AfK42ti@XcOGJI_fkc4AE%mPF10 z%p&QVz3o&Agb!fiYasjqtmc<#8i5pKo3psa=`}w7o@b z4i3xPN&xiWEx?y$fvV&eD%$hE{if>T%lCOjyr{1{R6cB7gO-8x%0Zld7i8<1{yN)V zp5)ILo|DFyYM@wvD8M zSRG%WjK0`w^#1v!^*yLv=N5zS3nJpwxJE6sN`nV9J`~ubwZ0DutwltBd@WS(&A=Z> z!e-()KUzgb@;vOQtXmuil|!CbnRYdp1^{k$16;>{HVCiIXE2g34qCT;eD*^t@~c@^o)om^irITMj%)`9i4DCVR=C zQYumr4wWdY%iFZg;S4o#Cf!>yPwiazY8WU6#m&De80as8$ASZ}ej)wQO)m?^qX6dw zrl${{308L%7FeQp8)yB)^3Ub5$DQ1zb@r7e?@zCpaS8pWV<#~R4p0aUn7BZ2LNdv9 zb0}A5X*#u^Zr162`j?V|r9vNGs>z{6Y11p`#FBdS5ZpKRwl~_gLvqRn=C|Lb9{rJIXk|)3Mr>3{f>Q$K(vku2j52VQ70ZvbTX2lGcb$fB}d!MuPRqQ$6&Qd zVT=s`p^!6z%aAOglg{*BqN91@R$2*yq;G&*fX}&CXz06LM?(%4pi_TU^ZJMD@(evf zy?oht%DAmr!?j(`kL(^E$T?gc9yE-8+-Fc+R73!iZ2_}R+*T#!L+ zNpc5gxMs}DsCX-`;;P7{#>}Bf)WzFfhiim-Tlzd%qP(_dR&lLa!N`mLSTs&Tj822g zjI|jvmG(LD3!NJf2g4v!!v_X*Pa&Q!} znHb1{HDXhB{~#5~C-4oK$cgUMhw(i95SxJ4ze~bxp}!}C&&a&A3>pjIsa~pOc6j5T zY-+tU^E*D8K5pDW&YDG%m^iGr(nimVZn5qP9kYqO$2S;oWjg!}Wfc<7l*Pkq??EK; zl_#D0UCJ}%pHvGMZ2G67DpdO}J{P_=N35ag?|c?%1k{=e2Nlf|q!Gd2I16qqGu+y< zdM1!0G|7+Wg}M$9pA7!f4ik)w0j`E2lsZ6&LMka(`Tm1Q!;W8}giS`sDS)CO)A>j| z-QDJq>1zrEIcu*Lj%<~{i^ctLEE-*0H3#EreITvMHn zQtg+4g^vKd_v^*^{91d91#}u4{v=Sw`ph=x%00-$CR{PsfExgoHSm-kp`^NB>z_qV z)7$19T^+90cHionsLisvwnP2DcywjDKa`dh@J6BM%`SW?m5Pc(lOvL|LgP~#o!q{> z`D)$s!|;iUo=?*d$){VmZjxfOL0_)=8KggESFM!`S(kTkJFTtG#wl>sF0u0`W&fuz3+)QXa%Uk*?*Rq-}XR@ZMBpe`g?{7+|STxFj_E2YPFywb`Ddn;;($H4e% z!%S}A@j-JvutzUP;)Pf}bS~N{W9U`8>E2kZ)CIL?H zT?oqv4C(puy=FZ-J?W$gyMMrxfWNKXy2bgczTfL|h7_GJIM*Eml!8N)yc&XSUsmj` z*1EB!#I9w~ma}&+6dOvcPMEGIE)+9nYS=QEAG9=ON?Ito&9!@8S`>E>K#7N144jKO zhVR2s|Fvl3Bh}YS5?<{z>8B)2x)DpnjrbW}@h53T{yJssRfSLq7Ypidt48R(kiPSh z2dldVQw;6{1_oXb>*iATEgu0dW(M_9a7$al8F<9KnEwhbOjh5aICf zz4*W&ea&YGZ?Y14kRf_51c~?AdfcVYfWHZCF}C$c?I+QDo4`+xxw`777SD)tK6GQ- zq%I+@@fouUKOZAU*RK>D=4dZx_@zzj*(th3)})XZ=%mwB2{NNpdCQU0>f7mW%T=8c zUWTqQ(Rumx%NSS$tC6YN`_uD=;Z65n_|lg?U6j(1_ZpdT+X0u3g*+|xdwmAYlQ)uh zQR}>m%~9gwqI2a*C-HizeNM*@G$>qX<*KoQO9n^XpnmLaCCp%k zr=EK~kP;|t%4De@zdsRrKD0$snB3#egsd!**k`DxA}F89&2T>9;j-|?Bb~4@8{^U4 zMhl@3>(CJ!{s|dRAAWS2;foQx=4^`Rjd>`ZItnS9GjFB?>^ihDv=54Bmj*)lnX>hl z6~$~B_>X)^X#%rM-dnS`5%U}ujXNx+8Sk!G=^JZ!W2<4mXZh^41AqAw|So zRoNZ+Gx}1fM~2xkN!NHBT>@t7Lnu+NTfWP(B?!p+m&@o`ZjasV4hhh@sX8|Kt$|pM zN|c~eC|t>2H2r-y1EtbAhI*-o49T}RpRFkJyZi#@DJpCo4Ot$R|5r@upY#aCTm%nxc`*qj6VRkNNPMEeE+v-)bWs~h+EU$g&aPAc91Dn+}gOT9*bCvfUjQMq|=FDTI z>#{<|tdw=4UTu!2w^*ju3%pMX$RhJDzyu~p>bGHRNvoOgt}a^b6e_!IZaZ3P5!N!E zRF4S^qcKf;!7QJaYt-=ik^o1G%Z+itcKaEsg!AMdl00$>|y4h2|aDsyLA zB9(VXxcVQ z=f}I8Ze5`~+L0URQ-saQXP? z4ajF|lvvz_HwcZt`7luvZW`mr%7W5NTx~3y9~}kF=Wiz_mNAU+_i=s;18m(AP`wPd z6qmBM3?-U!gT zS#*g?aLu)zN1MJ{JyTA$86l18`c8h8xdz!jdW=f`+lpUKe9#ieCK?d-qNj2oi)8lX zR(8d|o{US)JAS3g_o8K^OeA+`qBG?GUxvQ0{2zQQez?&NuFg-c>}z=9zFl_eX9GY6j65xgX1v)J5+SHrFUAwr>o% zXV4Q#H``dFVm;#%n)CCrTyXsT;1<`CO_qLuDG(2vA0*fqf_#_GofALTZka&UuGj1+rX9hokKvhmLlzE zEV@mR2LU|k{R1=NoZoZ4?=9@qyMCVj#L#!@d8&x>>f6D>A<0-2*~*h$3WvqO{una` z1&zebq2#ZXyHc+QZ6293yXvs%OvRQ_R}gTQYYkTjJDIW#xG)ua1U#oqI4jA1c1g%V zBlzQuj)L&8^&ftOAHP$Ty7PN}^`tZQ5x-a9BY2lKd+s6Y#)FPtn^H6N;dTD5Fec5; z#(Uguh@!XU3O2SA`};?4i|e@i^J$xsJ8uqjHy(X!bWy+YQCOw5TZnF+m*KB_4Fqfe z)NAt2m|S&^=}Y7NpneKTx}qW<&FH26fB{K=ZqFK~J>)3C!gu3;p z%qZenAVmya7dlFx;-?)kD_c!k&OluW_nns*`g=o!DF<_Cd6cEnLzyDlqJRZ{*vr(|5*(|+Zf6Ec!^}*xbxHPm5yGdgJU;q@Iq*3O{l|LoOvPL zk#EFD>~bzC;zUOeG0w7EP8s3+c?^NR;vwS7_dRBN5>Q{&Wly{Nc`f|dYAbi!c(KsDhW6cS=7tYdE{e5czSzwZdLIH;h^po2?YGDgY^jS-u&Pnt%1xPBy_hHlc<#p*0B5)CQmgg~D49%5zA6gU< z2@e?r?EM8cZjdKlvi)eSBhYlgK$V$pu`jwDorM>eb^|Z2e@39S@oX2d<+O-5h*&7}bjBvJ-X9xpv;j?|2 z1HJAX@2zB#3t!`}-RM$(ZsU7bbJb72LqNHoRV?~=H*VaI7AgfIFFG|{CgDy@sCrbF za7U&?snONw)rV~5ab)4gPD%KjX}C^-cE0LKCo^W9DloH*KR#cZ zd&a-P*xcAxDwNc_7v;|TVd>b+6ueuJrzN-$=5zdmJ2Tr-wiW5~MPbOFE;PcN{ z?**)AvyIN)JRPBFK-)7^!(x;EgW*Ii$~Zjq6r3b|ehs5JzcfQLUtX`^Rj`$RCerxA z1l0*r4uf-^Vg#EU>YoX^j@9!nr`0It#YRv*LE^pMUx>9;H<=I7^S*+PjPE;r!L4oNPhRT1TRHZX*0xMw?kBoK;s9C%lzoDd`+u7sY_$&q?k24O!8cykznk4 zHM&9f(3QWvxK+U_u5POIqYX*&nxOQ-vkGrqJ~WAj9?waB>51n4!R7?1iH+amml~zG zr`*-}N~5C+igf(m%;{!74*3lGo+u(jH-^e@c}(zl^s%a>8;+TrQC0Ak@bh{=72wQV zH-E9$2 zCu~eWrYp!6rQ%|pk+@c1SbRLP5PAMAZN(v3Ey?PzrDu`!Q1e&5kKHtl zy7scCmbuntJ?Imoxe69oe3hh(p?um%sS7bi-EMCy%pue>Ck5i=EsHfh#7Os5$hLpHx z&l>MU=7k{|k4nCU6R4Vf3B~j|&1VAP&&ilJWbY27-ZAb+wB5}dyWLzZN?QG{%@lKo zC@kEKXv$UNl~jc%yI@&g{x*hXerR}2wJhqP2l}L<+?XP0pADd zmgAp1QVYd)7|UHr$`Y31g$c|bbZkX0tgKIm%BEK)E^o(f(#WMC(vKO>YkS3^UKW1) zj`lLinbQ>WAud|L$B9RY{nW zlC9nS;;xG)!u5Kq@W!_p5Ak0lQBlNw=A+>qjOLCP?$SVGiBO4v_4?Iys$&# zGWwd-uEiF4FYz*&??s$0C3oCIar@?XnWaYAEM%hXU}MGNQ7S3o$=1Pv_I#4`ZpXHV zrcKvJ)AK6w`L4UM9(I&6#I(ogaPeIW@NYcij|<03yZ;HBofWMHS3mPVsrvPdf9Ej*jmY+26yDySHYZSJr7cz=+ z_c>U{qfC2OR%#e9y*d(9$G7q3i4ua1;p0|L!#K$uyk@=}#)N;zdf+apo7dMI0gD*|dE2jFiqP6akA-!?Q7pX}&ZzAv#LGRol2>*|Sb0wP8Fg z^djc|v_vaLiRsR=@mht;#$`dpGY&$^Z1xCW>}Q-;nK!{u!YWz+8@mNGWX99YBBMsBUyEEKnWq>qtH zI)Tz?Q?;u|;=NYc>F^i9hc-}eVZ^@TM_zt4HyTbU8DV-RIPeOhM{g7O=v=VG#x*#}cl!9BG5+Mn z9(LD@QV|oe!aVCn(NU3zo#+{PKRY9I(dr2W&qwD_no^=}x@kttHaO!B52s58$n+Xm z9UNzzv(qyc%8w#!N{GX4xPEYJ>k}85f<(TSkQg_&Qb@#2=t_fHMu1DK+dp6R&HZSk zzWLatl8=bju5*L*=Y;VW^|zk!RkiVQY|Rp{3{<_)^V&dz$8Y>EXTFg|^1bJl;__yD z^!;S31!RCS65pvJd~iQ+u?HuSJEqVy3~VjH~#hq=JCZ! zZ!059odjvVQtx5u{q57?StO2;XV2VLokj+u8#I&2JZzQJ?8>3%NVt(`II=#{}3< z)S0x+=?p!l2d8yoG&6Mx=h17z1@E{w_cAVTK2&aLDEP2vG3o&)Y@l#IiYub_5R8_%h_5#6;`;i}3iQI4$eOIOGQYi zhd;7Q4y>r;(vef$Jd1cQuHPRpzlx|>4#Z0s%e!A@7y9DEl~)0rc5d=}+qa{%Z3cZq zEpXqw7_&S}D*TxC|Iqc-VNtH@*C2=z(%s!TAPPt$9a4gH4J9Sr9U@4Bbc0Apmk3A+ z4Ba47B8_y1e9!21pS{m_e*VRE2{Z5e#C@;3)%xRO!)G${%(23}?a z_G{3-zgJ&~#o_NoiFwA?nLsl&v*gjXWzWRv-cZN*uT1h`4S;wV-Msdc97V zoDGDC8uhSzhyw2&?~Y49LUZ2p`sVyqJLO88Ql#YwU+!J`?O7|REE7+9ulvtpBK6O* z&1NZ(D}tZT=~CQpd*f~0K)bqF?`E#5ZVsTToivaEiSsuj{Ika5&I7ga6bkLlSKjSjpgOah*rjVFVkkTuONf2-V>aPyEV?U~@{1Y4 zH}CaMjHN+!<5d|K(rs|V@`-IRyNABNPH#n0Mtgj$%D-T?l5YN4NlK4#TqiOqxX(C; zFjA?OOHTMq>40YS%w0-BWt%=RS!jWgN(b4kQ{e*p7ni_a*|NXOm{Qop>=wqL@^jdc z{N`hBu=0bgyJJ6fCXmqm^eU${W1n^fwB}m>iNje9N%TcW%j>J0mQ^J<-pSc=?;9{nf@N*#ZD=vXAkP^%dyg;3(?Jil z0N&}2W(v9oIz+(s!1KeZdD38eZdtZEr1}4(kTNxy@23B_))y6hJ`cIpf4ULx5R@0-Ai zvgln7nIR{g$Rc_#{MRoRzSey6ZzkxEbptJsH z#^+N0S%IM+QCi-!FuLS3vqc`ES8VVB+pC4a2RGzB$s^-z$f4v)#(T3ew2%|pX`STd z4F}?Rv867Q5%2r*7!NW<;~%IqE_kjyhp`v%;!xV>NA4_>CU^9i+CM2kf5+-?_rNdmGPcGR3hg}$)_d&5%p z^+`Aem&wL){iy8Bm1c}^2N-`w#)MNt5~~)0tQn=DN>Z`rdSI=jAWQr_V-tJ5cVw`b zsNw7zrUl)?);`5Od>%FPhLAhyISQj*H5Z=GvPnqU4O-x)&mUj?Glcjn zXSOA1b+RB=Da6Sl5|W{&r4rSkS$Y-RJi*@Yo}6w$6!QPdg+9eFs-Eb(05WK+1s z{x}C?6Ik+o*!|y2jCIx7y2TF`I47){Rs5aSY+|XZa6Ob=*p)^sOev`)Q@lm*A8B579|D}$uz`c{j(|lo1y>x~OjON~Y zmSvoi^5C{jul~A<2a*$F`v;nTB|-l1AY{IHlmbC+rsyymT@1%cTJx?jxw*sU>onzi zJ^vYaOVF{(2kKD2>cf#F#C%V#+Cga3ld!MVT1I`@NU6^jdO10v$l%6sKE`<@xINoB zy-48wGhjkttoI)5osx->(Sd5*SemTpy$^3LmxhN_!`aoaV&)JI+g%#}|t zdnXJS-k#wFqsqrUv2;pvxL$xzA56=Ddl_g2%%)i^P6Neo$7v-&O{eZ>df|>wW)&BR zeKPmaKav!SM7${v{3|_owi1DF4NuSIJ%CQ*#|=SHUeAupm7k0H^)n@PUG|-B9q&|; zUw#ozZ-Th7ISz6b)$Dk%M>0EVRR6 zvE;vFQ&08K7pvcTdC~-mL=W<$(l5 zY5SKX)%%*w+m2fPwQJ2y&RH_o9w)fUhE?2VTtCkE_EEe7L|pjmu3ah7M@U?62mY}h z6**@g01XdCPdwde%rAS+t({&QclpFif^lCD^-_YI=cC~{a# zaeC;!Fa7lFFm9_j3XMiX{6_)L)Ika>6~eqB*z_2KWgL!Z!Bpx)?-f|0N${hKlOLeT zMn2|tsxkcF{xdNkqL_l^7fD*%R-J$JN{-UiWxD<{)UVoN`a$b~r`O25@q+ubryPKN zsJ#C|^zbcjAut=-1MKhq9l!d;d-6boBOvz9``!CC%mz2;|LDykw=cw?=rAHXm+X|u zKIS^S*u8ieyG3`bu!r(#Hsa+??$mIIb8;k;A|KRQIiB;AO2cwveW}6G{b{_jh}TgM z_Pvd-JKmSalJu}uSp7)~fl~)>d0BwJvCoC`LonC00^S&0wr6Vpy~ggmP-3d9;h(K! z20tD2y~OGK+&!!>uz6~!#2yIk`iYX0R~elyhEVc3FB#bThOn!De!sPeZb2WB?9LX< zWpgFYhiBoR;WhM4BB~m}WDe<5S>~$Pd&+aJjCK6?e;x?boZ&SQi3Tb;V0!lP@0PK3g1?Fue<$MX)ltqI^k;EIYYvNs)aMylZf&H` zGL{NFbpL7BJfB%_I_zB@70Ei3ASb&e%2Rfee}tIbS%ZkWfn>w_tQNT)Pwft4MNy47 zwGc_U@z4~JznPhPtiDpVN0s;D!2EKQPvCT8diaFO7>bG_+1Yg_$$R#zZYy2l5H3mX z2G(T$yYq^D-de}i^e8k;@)XG)mSw~^{C{4LRZ%eo%=3L;UH!#Y@T<)XZABO00gHju z+hJUwHw%PNpiv9H11j(xh=Kcq5CdxBD*{!%*wJoYWs$&^bs(*?uRj|RJCK1)Hh zw)6U9jQ%ZWx`w-?SI6(g4K2KeuPF95I}l^dVNZ11tYFxOA)3J{_frcb6cIPk^**@r zw6@WB9J+S$)|;4Y>c*>Iswh(=CrhVO5ONUH#zRmfH9jv*=*S}I1$mF6i0^maQ(1fb_A z=TF`{Y3c7AB)qX6{x%rLH1p49t=kuvu6?JY3X2My8xtI5>t%os`se7jl`Y9`B ze`p$5$s{HRe5ASU6AcD81vR88QGSPoOr7|C_W+^6mGB zsB5Xo5NaBq;aJ`~H8H|WyoLE#ndyQKI;%pRdW$v*ksT!uR@uQ>K-nc1Nt0AlUo*b; zmC0_Q#pt17ITiYroR4{Bd_(I4VeZIxhP+=pm_U!RecNknZSuvxm*kozohv8Q99B`_ z5tS*B+=H_H_ zUUcB>`NE_8wlhc$rsn z-YZ=otSX6d;Euhlqr5OUd``YGb|;{w|NeSU24ehZs06H+1oKilLP>EKy<1tCDm_`^ z>P?5mNu?^2^Rx7N5hb7JxB_#!@3+${4mo>&M!w$2p}G`DoGvgb#2}H8?9I=6U2_QW ziYS}vm{(DT`rdnIf6{vtzTu-S(3>kdzSaAvCdmLgThs4m>2t|Y7$Yv{+(q>b$v1VL zs#uH&HMhQZz=N0QPuB6a5xCkU@bRkO3!Jk{a-jf*XYCu7P(Z83uiL$zMhSAQDD~*S z<^)K(U$S%*j$-Icm<(^O25AXrlu!P=NaSBNnHZ9}?Em`nbEKj7)b3SJqPs^ETbqtCajMbjFa)u7r_oERo@GQ)zq!(`6=%M!NI}=sGvFXFA5$ znLT{q{TJNPFh$oWm~kNnewr=jz}I_%Z(gMnCM5HJ%Co<;%BA1b z|0Y2C-r4@AN6fqZSt9u*9T=f|9TraD{HNC)>z5hmy~osE!c)&l|L)kn$iYYX1e(b*Ms=bsCGktJzL?S8sRLo~gkqu8yy2{AJvW%K_L?dK~45SBzE zzCXMr=oXTYOOZtJ@F~VM^pig#m{M;3exMbh)wZ2C4?$cwfUF0#Bfkz&ET;KEZQ z*uzrn!H2_A+qj9I$U09AtZBi5^(c}+l9HNHfEDB&kqiW4@+&9eseKJUxzZ%(3 z_#BR;Ot+VLXyev21&#)iajhK*l_R&4FMnLH1(6urWWSatDi6q&sJbZ#agM~0{1e~6 z!RM7C%P07(L5?@Pz6#i2seI3j)!ht9xsAjCwE@1my_9B~GCY2t@MMa2NNYA^c^pTy#N;5wVvhTa z%iKufv##?9x$f%H1gC1Ne=;dw2~hbQA*VuI((9iB_lJxU!g5{KsbTIEVU?!qAgQ(LsuI=NiMfj6;p|N64u6+24^I%XvND4*?5BE@Ubm1jlYUEt0YlS= zOS8$hRzbDLq1O=Tv^H54EK*fLstB_xxHWFwD5L2X8ROIRG#oDtCM4->qZIVJsclJH2UaH)Hl) zev7rcXjnSOTW@p@cIzmAoXphiWL@WLMZcp@kGvk9d~@I5urM-%lcbOFl6x!o_@tIZ zIXB9m5`TM;rn40araiuZ;xLH+H99 z)~vq`KAy|pREeMs4xSqS<5V4b;}{$o-l6Yf5_4yRVPp`r{lm5XJ*D#EiXWQ3eeI>2 zMG*b5@oMBjs~7Qj+Sn^Y(Wy9&p^Ln&gfe~HYIm26IMni{=*%@6guF8=*mO>ZD39%8 z*T=(}J42oa-#K_m(-}kh%H?F~6y`Z+5 zMj>55BAB!dU2}{=HEBWNh5p=~Hirz;&E2;R6I-|h-DnVrFva^OyS03g;a1mg^DzTA zv57j~8}v5yQ1unwlrFUT`_dLD!Sq*|{SOoI;}T(WiN+y@RcUtNw$;^EdYv)3EHlrj z5t~fdPJFC}6Dr3LWl*hrPO|3Zl-KnhhNeJTGi6Qjs-^=lbU0_*f9!t=le5t}cmisL zgvl&;Q`+yIKHcz%CdRyIxgVZ7uZVG)b6w7SDcB&=@-+H;wu*V^mnqfFr?^P>n@u}Uj@}5i*)hu~9emEa`xs*ESruFkOMy=`Ac_R|OdV-AILE^k2 zYCV8R@Md)81bcXRU1vi=E@Ju_1B7*ehYn0SL52VODC1SILbX0Rq<0sT! zsxN(IN0s`B;ifKKu$GbhO;C?5+Ft$hj-uG9f}<0ghILH^ZKZ8^GH)(}0!$yxf*!p# zKOU-QsnnaD+}vGP_1FMcjyl|BDDe~8(EHg=jqcT_hGxwj??*+ol&i5fb7DNCLzPJC z46sNXkfBDramg%_GXw7(bb7=>m-NM113a>)_fd?K1m*T0eVF5PaxT+KIcSk zvFDKXxnxJpnwG*iEp)L>+>&otIrO%T3lb?H@hlEiYsn`rdbiM=PY)3 zl_z8hP|w81yHomPQmf!S$zB1`6npvG(NYvShuwSm7Y=z%<65jqv^2ZI)Qp&77qb+D zpq{*$*?(k z&*)aiA~CZHgD^86t+^_Sfyw!_In&^|ZeBd~bw~Pf8KY&E^oa4%>-<^=p*f6~zGl}q z)o+wZL~*)4ClO|*izJ`pe<8+eN_`U}PX3CEH|(7=!F;$C5?1DQhIFjD7|q*!JSW6l z^J~6WiD9MZ-FbL;}&XdJPm&*8EthXif5@vvwSC>@tfzDS!B1zHakO1`-KC{It9M1Y6CPD zpUiJ5P(RG2`$bv^M~`qdM4VJ-(U&AltD1Q+qSS3h@F55zMHWsdn?ClrGGHUUoP^Ft zy^t_gd@LWt;jUgNEdc2ai9VQ0IRD5ZH*`8W1TM@5BO|XIXpp`))O33%T=hMdlJ_g8 z@`w#2b#1__rW-Sz>Bi>DxhG{&p!~SNoo8i=n5VgQbYaKgX>u|IaI+}L%Ll?~Mlq6j zI}7`daO6k%@Qb-oDZdzf>3K!Kwzvm~G9)5nx&iBggeeT}Sbs(K|9@NwCNxM`@VvPu z1=zx(EFGY4%ZMa>?qJP%`MpSnm{f3CnpByialAP-d6E}6l=4jUOYtXZYKs@Gx5&+o z$%Pte&E8}4nvid758?@N(sAVLQtG4#6V97bi}wX(ss?Kglh`>8?m2op|CI3~?@;w+ zq)D7*I%q2k_GWKlu~Rr4wM=4CU`hCN?a4+i?adsA)4VHw@{E!H0Ewp{I=6WN2{yD}R?l>UF^&oL@lf~Z3h{AYUr z`dQioJdvR9VY&+12e>1CM=EHq{6Xa#3_7uQ{AVHtTh8avvQ%e*^k+NO>u1*WVwJJy zPxo;{PXOscKHoHGZq6Q?Ju^Qrf6S(pFrN_c^Q7W3v5FzXFz1!p`+UexQTpNziuYn& zR*H8SyCThDN>Dwkoz{`E{xa*>m}e?11nc-@A?6~r?{cb30#YGdQ#2jYQ7x-y>zDY7 z5jxEG`x8qdT#nZ_b?FwPVL}%cF zrew4S_4@rAn#$cxbHLV{L%zH1AZbDt&v%&Vs=$57f_vAEYM#pdapRh2Hwogy%iwO= zhVI!i(vsyGCb=T+SZmeTI#?p<{T?5_nWVB&t9d3w1Jfm0=6orK?;fjsL3cIiH_A zm;SN!(h~}0i*vVDhu9aXS&i46z{TE@2u!vTdBlhq)kvSTh`Svb)*u{E2b=GB&PMnAxFKNw0r}cGj!5DbjWm2?0jZ;cj}+?H%5DDGMENlKQrs5k8=n~>L(Nr>(y&;)Qpsl zxh3(-AW9bq@gP#{I!kRRrF56Xa`HKmB%AZmSrrP)&2JHrj3~bPm}!=k{i+}#{;S3t zg0ip5cZ6NLe8xY6#p+ob9HDI)vg-sLPTL%vKErY6BDdFbicL5|`Dv9qRgS(rKZcrW z&)Y2O46U@Vb~=oF9`}!%jpaik6BN04FY;YIkNm~UGnPlT8ynz|W*eF&FqOpfVK93% z&5}zR@zpjao&j=7ArZ<=S$?a)z5+GfJL_#JPrXbMdS(+fj|jKy>)QkeS2o?f9^rYW^P=ysVrloC@16s07HUJirEOCqt$@S#ENIaFS~2sg4UHv*Yy>RHI|~ zP@MyCeYo^_S->%{KjUFhbYYDvaGmj*G+iS?F<3|nzFQr}hidV_1olxQ473Z`ibF%!=q?_|))W7>1U^`uU|K+ZE8%CVB`)JvQc?)v80QvJwd*8|VE4fBGC zcouyUt_URC;91*`QCFmVDpT|{SDOM##jydr*1i^}S^&7iO<)F`evix008lD+s{A9f zZkYQmu9shNxo%j+n9nHmUX1FGxbgp{&hDAl$&ict zP;gq7KF%yHUitFiDV4T}z550$Bk1{7tCKnJUotRy_Wq~5VDY-&4qLI!TV8Lpk-K#lgRB;La1QasP!pKcM>XSsFN6Cw2EXkWWTowR6%o*K z!sEO?45&lHe{uc%r)TfBl)-2ep7NdGM&8@(t36WPafv>ny4BGOC&c3I$Sn8xBNa(( zamU!4!zcz4dN;&GM6@Stt9sc#sH?OT_N&w=l&0XP+Lg-|7FC>HPzvqJfA=~8G+1N$ za%U9dIX$QNOzW&nI6J(~C!H}?&))s$@$$_va6WzU8E#EA%_UJ3@AD_s~VuSLV69vIA)&eE~^wt~UvKF?M_nHMDEeR$Ky0=B2T zEZIRm3LaHI_Ok{tMJ)*^u1CsRmh)P=2b*xuGldbS)NY^6uGSrJ`aGS5?}QCUxk zVBhLU0%BXp?TZKaJ}Dk5@q3v&TbEz`=u+C8hmPML_}2}i=PEg?ZFqLnvc<^1%d~St za5*xDoryHH0__LzzC4M5(LoFk=(OR{ecuO!b6^mYy6qnf7UE09Q6}g}OVh;kUqQ2Z zM_&Ts>$maA_=5@OZ^@pq)HzzMq*?S5cBL6SF(^_ZM+;G&4nS7eATQ`HVacOXeXmC6 z|A2+Cj(XR=TvjpQ=uMBZ3RIr?f!l-twIr?jYxF0ypc(PgvC&7|?}#)6Nt zlycd~AI9Rpwcx~+y*c>wIzJFx(|Vh}h$x>18TZCH#PN|ZmgURspZ`e$VXK2f6Tk>+ z?hiraY~OnAI#UJhdV(x|1vsDn%<=waWU`qCBLxh0YOkgCpToq;FA1&95Qdwg-j$H= z$VL*>DQ-7TQG_APjL=JQvk;1I>5$|T*UCByHkcd>yS63n`MA;nFEtYf)1QhDp#Lbm z1i&AgPONPjNmoRyaN3X{(GkJsb0=lwAW4nQ;_;I0huD@HUA8k{yi3YQ3p|ozk;mT^ z_2;XXz`bhg2WB7AhDn&FWtm|KlOTj0`tBP&L#z11yTwD3*TxBKa?&W3uVaqtb&p%4 zL=;IDfNKD?q;x?S>%nvZI4R8UsuD1cNl7S5HrvycAP@zEf}w>NfymLI;Ubdj=vLbz zVD1b5n_-EATm7>kAaFl%p?=tuCZKn%|+`V(tN+giR52-uz;z0;X+rY%C}IHKni)h`IpD5}>^5yRq0+Tzn21 zQbp|u<)kEDVdq;-=qQAH%Ia#cj<-B2QsYbV+{}^puzn{$q4ubtMpoYBTsQR#i=2*x zJZ~?t8y!+ET zybuxib6+v%kpWs>ZkuWDgWfy-@}`dv{C%Djw0($VMj9&^c>ef)#Ldyl^#`7p5Ns%@ zYSYO?#V`^Q5Om!^Ku|`JBB939{Opc^aG5P16vB+;6#3ec`Uov&*VrXqalb^AErdB9 z{7X+)6gl_51sDhUr62=3}yZE5E2Oi z0-tp>a;zVxeWKkG+!&IlfmsG9B6cyFC84UKAZS?tx_CgQxz>z;K&JXQA=cy2#dq%_ zjzEKC84+PSi1i*}E=IpGqq0V+X%I6K{4dt1ZqCBqzGd3IjWB&ziiG7uBR0nqXyhG) z3any2?UxYl@*3Kpeg0;1USM~@zfTtdf}y5B$I7>$h*$zW2s^lzWPSKPRAu$&L(!SO)xa5!(3pelI_%z5OoW zG1xaaPKH2Vg@xVuzg`2gVoNflFUaHV@Yr%awqNxPCeC zWgxWuwH;Ym3xNB&+iSuUG${kIe*18J#j-QEAe4rg_)TP5Bl>$UF0Kaak_W|NFYj+9+Pnx~{0 zFBXd@87R3cdQ;0yYM_3%j8@UkJSxgwf~k;(e0}guKYK0H4e?;HE1zG8RaM$coj_dy z!Rqpr0R5m1^e1ZisODY&-@OO)=zy5?`#n&C3S9Y9I=>J+I8yizW5z%Ky19Xfq?E{?wT2J|S1i_mf`#2dbHP7LiQ_?iI znIoRcAN@_Y^NMKIt0iKcp7E%$wfhUM&Rxc8d_z58F)u5KoaZ~t`*uW{T#zV{AOITc zWo7T4e@8+a&fTJ`R)nA9fnZd;+`K$sRsaPs1vpo*|8=o_CmE8Xh8ktGl9|VNgYB@r z>SMVZIDKeC_tabto!DAiBce$fq4RS9}B7bcodZ@MciH?>4L z5#!14_MNvJtH5`Mfn8hfFZ)Rdg?X33zgR~dP-6h;jRS+@Gr%|ra#`K~=kjcK6$jP} z?Xp`br-UoL^Gn|lPez*CaIJK2OgZd$KKdXtp8@%DGz`j4g z5Bo|geZ4K7{N2vE$;sCEyzk@VwAGdSsZuEi(YHy>kv50(Fi*cLnDbX5`VcaD-JP2s z2{%W%9DNs9u)52VfEQef_!#rb>7kNuGru8qsrGNLQ}zz1f|!}n?`pzDKw_Tu|DW$) zs&$tlYk|KxmR?6LxBuRlu7u0g`blGeb5ng6>4fO@L}@W`1RnI8VV(@ZW#&l8gALRB zDjulOibEque45)g>_4Nju0t-E_&B~@*RT+7C$;@~L@gk$`r3=;0_n%8-*E?+NJ1Te?zEv>MI?Z8IdwZIzU=nX@??zKy zFVLozK;!yRR9{? z?(~@@7XXiycN?+=2OMP{Co>j6gP|XI2S8{HsCxgHppko!H|YQUkif;D?X;6czsWE+ zZ=|oQZ+g;-t1qhi0fE1AE+gc_&k!pmq;=#^CNa1kQ2|ur$LTf(dMBO!z-gLuJWpkIYTF zuQd?exs`yv+dH zu}B{r64DHG5PEM0{{F62T zU8pECGcz4s(4Q?`9hf>F`PQ249Q4n}t@k+##8y*vKRf$DLsXSsA7VZ4tW45}T}uBK zbPK~smt|8{QCUMmK+yeP*BFjcK8%m7*}AtL&PEbSlvuBB1QuzXO$7N%h?=t#jZXGIa0a=N8=d~az3iKNI6IFIl#^Wmmd$(o z;Bf>1UNUefocj4S+3Chu*lF<{JSbpJYX^w9?tfe;42;5@4ef+jRQOjH0wOJ8uaoc1 zoBKeG0e&L|{x_l|l_F^hhX4te5rl{M2Xx>4-nixfN@8Kpqs8XUHmMZAg)fp#Y1x`R z{;+s1@z(!%0VD2vzy|h%{w6@Vqa<=Jrn=1ts~F@&z|8l%`FXWF%2{JMk_$*R!8&YH z!?Ldf)efgxeN6B z_-dK>_-X)&Irw0>Mm;CT{ribnMPZHC%6M^k#@vnkJ`bO}wu8%lmX)9mk3hQa&C&F1 zKTc5khpU7y+g~@&%0hKD{1{OT9q@~*`1%4i%|JTm6e2_KeZaB@?0O|YOJFntYG$^F zc+6eDaKl7=b33TF_Bd-)$RJ~ye zpq7e-2X%oO!4JFw#8{x5yV#b2*7~gs3y?No=iajYvx#`sm%PAnpi?WV!M=T zXiXCk8SwJ-Yyomysmi|j*qS@)I$wtas@tTs5fF&l3zsq(u%Td6e;wx@{3kXN<|)`v zv1ekeFk*_FK1&!V3`s~z-ly0CVN+szel7-lI}T4yd^ZZ-z)8_>+S8H1heGUI2BZ5| zZowE&cNgAVJ$Quh={EI1l6@~YyeKGR!_+WvETM?X2|Sw$Z;YoL*N17qNdsS9z^$A> z1GvX8FD~kAW<~|3dY`U{FdVLKU4e)Q0ReuJ|2$qf*Pq+=gs=i18tFO?ZQ*GHMiYeV z;J1`5f%l-{;3xz6Jf&2=nN~m18zCpY;;(Pb=Djnh=Jf6&z~d(P5diRJBsVShaSCKg z$)6bscB|_ZMA~Zu0v8^bt>f6$#A1Y90Tmo?F%X}9k~aqb9qb2mFf@xb-U00VA_Et1yj}Zs-X_wI>WQGvtwdn zz@6P|&YJeX%X* zT>Bm9nLYxwJNI%3V4;(+PL7LfzoQtF8qd57(xej+uU?rLYRIwce@GCOW+)vm#@EJy zMt<3XEG;b=8ykZ=l+2vBK~M2(1K7Z(0_{*58XACpzgC*wxe0Q@1}{hME~!QI-!Io_ zCozK$o%h-mz6c`<1`W{%JYyOO>|o)vM9hUyQBgtUyiog`i0a8_ARQok4+vX$i5LZr zr%QR*ztAo>aCUZXKn`kKTv=f_w)xr+D=K}jbP7Bk5j2u?3qm2}YBN@N4?r3~X9dDy zqd|+w$0Y4Q0Rt|t0K~SyaXxGnkjaMm$VZTUkR1NKWM;?33b(+{n$M+6CG^5z)(b7d zzm3UI6+3Jk^kmM?UV=$9y(6IYgnIWbwgxT~=tC&KQd2cF0$<(p7_QuWN*Jaz!DiTU z1tO9Gult`0b$XY=b0bw1^ciVsa{<@_%LW)EnZV@|$Pxy34#=*S0n-a4#pf%Gk#4H1 zh5j6glxFy0LkGVJqHHD{Xbk`)eO1i7#_h-lfcB8liuu8Vdig|FIK3OYR0?qZAZipdz1Z)
41wlcKBeWZ^lke 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 W(>E65&}NtQbL`~Lv(B8-s$ literal 110125 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 - + @@ -20,7 +20,7 @@ - eIDAS Middleware + eIDAS Middleware @@ -31,7 +31,7 @@ - eID-Server module + eID-Server module (Implementation for the German ID-Card) @@ -43,7 +43,7 @@ - eIDAS SAML Adapter + eIDAS SAML Adapter @@ -54,7 +54,7 @@ - HTTPS + HTTPS @@ -65,7 +65,7 @@ - HTTPS + HTTPS @@ -76,7 +76,7 @@ - National Backend Systems + National Backend Systems (BerCA) @@ -88,7 +88,7 @@ - eIDAS Connector + eIDAS Connector (Receiving MS) @@ -100,7 +100,7 @@ - Service Provider + Service Provider (Receiving MS) @@ -112,7 +112,7 @@ - User with German ID-Card + User with German ID-Card @@ -150,17 +150,6 @@ - - - - - - - - - - - @@ -178,112 +167,124 @@ - + - Server TLS Keystore + Server TLS Keystore - + - BerCA Client Keystore + BerCA Client Keystore - + - BerCA Server + BerCA Server Certificate - + - eIDAS Middleware + eIDAS Middleware SAML Keystore - + - Signature + Signature Certificate - + - eIDAS Connector + eIDAS Connector SAML Keystore - + - Signature + Signature Certificate - + - Master List Trust + Master List Trust Anchor - + - Black List Trust + Black List Trust Anchor + + + + + + + + + + + + @@ -337,7 +338,7 @@ Anchor - + @@ -347,7 +348,7 @@ Anchor - + @@ -360,7 +361,7 @@ Anchor - + @@ -373,7 +374,7 @@ Anchor - + @@ -385,7 +386,7 @@ Anchor - + @@ -397,7 +398,7 @@ Anchor - + @@ -409,7 +410,7 @@ Anchor - + @@ -421,7 +422,7 @@ Anchor - + @@ -431,7 +432,7 @@ Anchor - + @@ -441,7 +442,7 @@ Anchor - + @@ -453,7 +454,7 @@ Anchor - + @@ -934,1504 +935,1907 @@ kgwBAABLMgQAACzJEAAAsCRDAADAkgwBAABLMgQAACzJEAAAsCRDAADAkgwBAABLMgQAACzJEAAA sCRDAADAkgwBAABLMgQAACzJEAAAsCRDAADAkgwBAABLMgQAACzJEAAAsCRDAADAkgwBAABLMgQA ACzJEAAAsCRDAADAkgwBAABLMgQAACzJEAAAsCRDAADAkgwBAABLMgQAACzJEAAAsBR1W7nBifhr mQAAAABJRU5ErkJggg== - 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 +YII= diff --git a/eidas-base-container/pom.xml b/eidas-base-container/pom.xml index 7fdc4e06..91b1b9be 100644 --- a/eidas-base-container/pom.xml +++ b/eidas-base-container/pom.xml @@ -14,7 +14,7 @@ eumw de.governikus.eumw - 3.1.2 + 3.2.0 eidas-base-container diff --git a/eidas-base-container/src/main/docker/Dockerfile b/eidas-base-container/src/main/docker/Dockerfile index a79f1f47..0bee5b33 100644 --- a/eidas-base-container/src/main/docker/Dockerfile +++ b/eidas-base-container/src/main/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM azul/zulu-openjdk-alpine:11 +FROM azul/zulu-openjdk-alpine:17 MAINTAINER Benny Prange diff --git a/eidas-common/pom.xml b/eidas-common/pom.xml index 6c9d28be..b94ffd56 100644 --- a/eidas-common/pom.xml +++ b/eidas-common/pom.xml @@ -14,7 +14,7 @@ de.governikus.eumw eumw - 3.1.2 + 3.2.0 eidas-common @@ -28,8 +28,8 @@ - javax.servlet - javax.servlet-api + jakarta.servlet + jakarta.servlet-api diff --git a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ContextPaths.java b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ContextPaths.java index 4ecdec56..bee98794 100644 --- a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ContextPaths.java +++ b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ContextPaths.java @@ -53,7 +53,7 @@ public final class ContextPaths public static final String PAOS_SERVLET = "/paosreceiver"; /** - * The path to the AusweisApp2 redirect controller + * The path to the AusweisApp redirect controller */ public static final String AUSWEISAPP_REDIRECT = "/ausweisapp-redirect"; diff --git a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/CryptoAlgUtil.java b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/CryptoAlgUtil.java index 019ee992..da9c6b5c 100644 --- a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/CryptoAlgUtil.java +++ b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/CryptoAlgUtil.java @@ -1,12 +1,16 @@ package de.governikus.eumw.eidascommon; +import java.util.regex.Pattern; + import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.xmlsec.signature.DigestMethod; +import org.opensaml.xmlsec.signature.Signature; import org.opensaml.xmlsec.signature.support.SignatureConstants; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import lombok.experimental.UtilityClass; -import java.util.regex.Pattern; - /** * Utility class for cryptographic algorithm lookup. @@ -15,6 +19,8 @@ public class CryptoAlgUtil { + public static final String INVALID_HASH_OR_SIGNATURE_ALGORITHM = "Invalid hash or signature algorithm"; + private final String EC = "EC"; private final String RSA = "RSA"; @@ -171,4 +177,56 @@ public String fromXmlSigAlg(String xmlSigAlgo) } return algoName; } + + /** + * Verify that the signature algorithm used to sign an AuthnRequest is permitted + * + * @param sigAlg The signature algorithm to be checked + * @throws ErrorCodeException Thrown if a non-permitted algorithm is used + */ + public static void verifySignatureAlgorithm(String sigAlg) throws ErrorCodeException + { + try + { + fromXmlSigAlg(sigAlg); + } + catch (Exception e) + { + throw new ErrorCodeException(ErrorCode.SIGNATURE_CHECK_FAILED, INVALID_HASH_OR_SIGNATURE_ALGORITHM); + } + } + + /** + * Verify that the signature algorithm and the DigestMethod algorithm of the SAML signature are permitted. + * + * @param signature The signature to be verified + * @throws ErrorCodeException Thrown if a non-permitted algorithm is used + */ + public static void verifyDigestAndSignatureAlgorithm(Signature signature) throws ErrorCodeException + { + // Verify the digest methods of the signature elements are allowed + // The OpenSAML API does not return the actual digest method, so we must manually get this from the XML document + NodeList elementsByTagName = signature.getDOM() + .getElementsByTagNameNS(SignatureConstants.XMLSIG_NS, + DigestMethod.DEFAULT_ELEMENT_LOCAL_NAME); + for ( int i = 0 ; i < elementsByTagName.getLength() ; i++ ) + { + Node digestMethodElement = elementsByTagName.item(i); + Node algorithmAttribute = digestMethodElement.getAttributes().getNamedItem(DigestMethod.ALGORITHM_ATTRIB_NAME); + String algorithmUri = algorithmAttribute.getTextContent(); + if (digestAlgorithmNotPermitted(algorithmUri)) + { + throw new ErrorCodeException(ErrorCode.SIGNATURE_CHECK_FAILED, INVALID_HASH_OR_SIGNATURE_ALGORITHM); + } + } + + verifySignatureAlgorithm(signature.getSignatureAlgorithm()); + } + + private static boolean digestAlgorithmNotPermitted(String algorithmUri) + { + return !(SignatureConstants.ALGO_ID_DIGEST_SHA256.equals(algorithmUri) + || SignatureConstants.ALGO_ID_DIGEST_SHA384.equals(algorithmUri) + || SignatureConstants.ALGO_ID_DIGEST_SHA512.equals(algorithmUri)); + } } diff --git a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ErrorCode.java b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ErrorCode.java index cf167703..31ab720d 100644 --- a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ErrorCode.java +++ b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/ErrorCode.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidascommon; @@ -14,15 +13,16 @@ /** - * Codes to identify various error situations for the eID-Server. Clients (both those communicating with the - * respective module and the receiver of the SAML response itself) should be able to display a comprehensive - * message for each of these codes or handle the respective situation automatically. Please note that the SAML - * status codes are insufficient to cover all specific situations in sufficient detail. + * Codes to identify various error situations for the eID-Server. Clients (both those communicating with the respective + * module and the receiver of the SAML response itself) should be able to display a comprehensive message for each of + * these codes or handle the respective situation automatically. Please note that the SAML status codes are insufficient + * to cover all specific situations in sufficient detail. * * @author TT */ public enum ErrorCode { + /** * Conversation finished successfully. */ @@ -36,8 +36,8 @@ public enum ErrorCode */ INTERNAL_ERROR, /** - * Request specifies AssertionConsumerURL but is not signed - will be rejected. May be returned to browser - * outside a SAML-response! + * Request specifies AssertionConsumerURL but is not signed - will be rejected. May be returned to browser outside a + * SAML-response! */ UNSIGNED_ASSERTIONCONSUMER_URL, /** @@ -49,8 +49,7 @@ public enum ErrorCode */ TOO_MANY_OPEN_SESSIONS, /** - * SAML requestID not specified in the subsequent request. May be returned to browser outside a - * SAML-response! + * SAML requestID not specified in the subsequent request. May be returned to browser outside a SAML-response! */ MISSING_REQUEST_ID, /** @@ -62,8 +61,7 @@ public enum ErrorCode */ SIGNATURE_MISSING, /** - * There is a syntax error in the request so it cannot be parsed. May be returned to browser outside a - * SAML-response! + * There is a syntax error in the request so it cannot be parsed. May be returned to browser outside a SAML-response! */ ILLEGAL_REQUEST_SYNTAX, /** @@ -71,13 +69,13 @@ public enum ErrorCode */ AUTHORIZATION_FAILED, /** - * Cannot get SAML response because another client action is needed first. May be returned to browser - * outside a SAML-response! + * Cannot get SAML response because another client action is needed first. May be returned to browser outside a + * SAML-response! */ AUTHORIZATION_UNFINISHED, /** - * The SAML request does not specify one of the providers in the eID-Servers configuration. May be returned - * to browser outside a SAML-response! + * The SAML request does not specify one of the providers in the eID-Servers configuration. May be returned to browser + * outside a SAML-response! */ UNKNOWN_PROVIDER, /** @@ -126,8 +124,8 @@ public enum ErrorCode */ REQUEST_FROM_FUTURE, /** - * The request has an ID which is not unique among the IDs of all received requests. May be returned to - * browser outside a SAML-response! + * The request has an ID which is not unique among the IDs of all received requests. May be returned to browser + * outside a SAML-response! */ DUPLICATE_REQUEST_ID, /** @@ -210,7 +208,16 @@ public String toDescription(String... details) { for ( int i = 0 ; i < details.length ; i++ ) { - result = result.replace("{" + i + "}", details[i] == null ? "" : details[i]); + String detailMessage = details[i] == null ? "" : details[i]; + String placeholder = "{" + i + "}"; + if (result.contains(placeholder)) + { + result = result.replace(placeholder, detailMessage); + } + else if (!detailMessage.isBlank()) + { + result += " / " + detailMessage; + } } } return result; diff --git a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/HttpRedirectUtils.java b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/HttpRedirectUtils.java index efd1f9bc..89be443e 100644 --- a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/HttpRedirectUtils.java +++ b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/HttpRedirectUtils.java @@ -22,7 +22,7 @@ import java.util.zip.Deflater; import java.util.zip.Inflater; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import org.apache.commons.lang3.StringUtils; diff --git a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/Utils.java b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/Utils.java index 6bdc3edc..14dbec88 100644 --- a/eidas-common/src/main/java/de/governikus/eumw/eidascommon/Utils.java +++ b/eidas-common/src/main/java/de/governikus/eumw/eidascommon/Utils.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidascommon; @@ -28,6 +27,7 @@ import java.security.cert.X509Certificate; import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPublicKey; +import java.security.spec.ECParameterSpec; import java.util.Arrays; import java.util.Base64; import java.util.Enumeration; @@ -35,7 +35,6 @@ import java.util.UUID; import java.util.zip.ZipInputStream; -import javax.servlet.http.HttpServletRequest; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -48,6 +47,9 @@ import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; +import jakarta.servlet.http.HttpServletRequest; + +import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; @@ -69,12 +71,12 @@ public final class Utils /** * Minimal size for RSA keys (SAML). */ - private static final int MIN_KEY_SIZE_RSA = 3072; + private static final int MIN_KEY_SIZE_RSA_SAML = 3072; /** * Minimal size for EC keys (SAML). */ - private static final int MIN_KEY_SIZE_EC = 256; + private static final int MIN_KEY_SIZE_EC_SAML = 256; /** * Minimal size for RSA keys (TLS). @@ -302,23 +304,19 @@ public static byte[] readBytesFromStream(ZipInputStream ins) throws IOException /** - * Read a key and certificate form a given input stream. When reading a pem file it does only work for pem - * files containing not more than one certificate and one private key. Providing more causes unpredictable - * behavior. Pem file containing only a private key or only a certificate are also supported. Reading of pem - * files is not supported with java 1.5 (also, java 1.5 needs endorsed xerces!) + * Read a key and certificate form a given input stream. When reading a pem file it does only work for pem files + * containing not more than one certificate and one private key. Providing more causes unpredictable behavior. Pem + * file containing only a private key or only a certificate are also supported. Reading of pem files is not supported + * with java 1.5 (also, java 1.5 needs endorsed xerces!) * * @param ins stream to read the keystore or PEM from * @param type keystore type, i.e. "PKCS12", "JKS" or "PEM" * @param pin keystore password - * @param alias alias of the requested key pair. If a wrong value is given, look at stderr to see the - * available aliases. The alias parameter is not supported for pem files. + * @param alias alias of the requested key pair. If a wrong value is given, look at stderr to see the available + * aliases. The alias parameter is not supported for pem files. * @param keyPin key password */ - private static X509KeyPair readKeyAndCert(InputStream ins, - String type, - char[] pin, - String alias, - char[] keyPin) + private static X509KeyPair readKeyAndCert(InputStream ins, String type, char[] pin, String alias, char[] keyPin) throws IOException, GeneralSecurityException { if (ins == null) @@ -357,16 +355,16 @@ else if (origChain != null) } /** - * Read a key and certificate form a given input stream. When reading a pem file it does only work for pem - * files containing not more than one certificate and one private key. Providing more causes unpredictable - * behavior. Pem file containing only a private key or only a certificate are also supported. Reading of pem - * files is not supported with java 1.5 (also, java 1.5 needs endorsed xerces!) + * Read a key and certificate form a given input stream. When reading a pem file it does only work for pem files + * containing not more than one certificate and one private key. Providing more causes unpredictable behavior. Pem + * file containing only a private key or only a certificate are also supported. Reading of pem files is not supported + * with java 1.5 (also, java 1.5 needs endorsed xerces!) * * @param ins stream to read the keystore or PEM from * @param type keystore type, i.e. "PKCS12", "JKS" or "PEM" * @param pin keystore password - * @param alias alias of the requested key pair. If a wrong value is given, look at stderr to see the - * available aliases. The alias parameter is not supported for pem files. + * @param alias alias of the requested key pair. If a wrong value is given, look at stderr to see the available + * aliases. The alias parameter is not supported for pem files. * @param keyPin key password * @param strict true for checking key size */ @@ -376,7 +374,7 @@ public static X509KeyPair readKeyAndCert(InputStream ins, String alias, char[] keyPin, boolean strict) - throws IOException, GeneralSecurityException + throws IOException, GeneralSecurityException, ErrorCodeException { X509KeyPair kp = readKeyAndCert(ins, type, pin, alias, keyPin); if (strict) @@ -390,12 +388,12 @@ public static X509KeyPair readKeyAndCert(InputStream ins, } /** - * Read a certificate form a given input stream. Reading of pem files is not supported with java 1.5 (also, - * java 1.5 needs endorsed xerces!) + * Read a certificate form a given input stream. Reading of pem files is not supported with java 1.5 (also, java 1.5 + * needs endorsed xerces!) * * @param ins stream to read the keystore or pem from - * @param type for normal certificate the type is "X509", when reading a certificate from pem file use "PEM" - * as type. This will also return an X509 certificate. + * @param type for normal certificate the type is "X509", when reading a certificate from pem file use "PEM" as type. + * This will also return an X509 certificate. * @throws CertificateException */ public static Certificate readCert(InputStream ins, String type) throws CertificateException @@ -404,8 +402,7 @@ public static Certificate readCert(InputStream ins, String type) throws Certific { throw new NullPointerException("input stream to load key and cert from cannot be null"); } - CertificateFactory certFactory = CertificateFactory.getInstance(type, - SecurityProvider.BOUNCY_CASTLE_PROVIDER); + CertificateFactory certFactory = CertificateFactory.getInstance(type, SecurityProvider.BOUNCY_CASTLE_PROVIDER); Certificate cert = certFactory.generateCertificate(ins); if (cert == null) { @@ -426,16 +423,15 @@ public static X509Certificate readCert(InputStream ins) throws CertificateExcept } /** - * Converts the given certificate to a certificate from the Sun provider. Some application need the - * certificates to come from the sun certificate provider and do not work correctly with BC certificates. + * Converts the given certificate to a certificate from the Sun provider. Some application need the certificates to + * come from the sun certificate provider and do not work correctly with BC certificates. * * @param cert * @return * @throws CertificateException * @throws NoSuchProviderException */ - public static T convertToSun(T cert) - throws CertificateException, NoSuchProviderException + public static T convertToSun(T cert) throws CertificateException, NoSuchProviderException { if (cert == null) { @@ -485,8 +481,7 @@ public static X509KeyPair readPKCS12(InputStream stream, char[] password) throws * @throws UnrecoverableKeyException */ private static X509KeyPair readPKCS12(InputStream stream, char[] password, String alias) - throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, - UnrecoverableKeyException + throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException { KeyStore p12 = KeyStore.getInstance("pkcs12", SecurityProvider.BOUNCY_CASTLE_PROVIDER); p12.load(stream, password); @@ -513,8 +508,7 @@ private static X509KeyPair readPKCS12(InputStream stream, char[] password, Strin } else { - throw new KeyStoreException("keystore does not contains alias " + alias + ". Try alias " - + aliasBuf.toString()); + throw new KeyStoreException("keystore does not contains alias " + alias + ". Try alias " + aliasBuf.toString()); } } @@ -574,7 +568,7 @@ public static String createErrorMessage(String errorMessage) * @param strict true for checking minimum key size * @throws CertificateException */ - public static X509Certificate readCert(byte[] data, boolean strict) throws CertificateException + public static X509Certificate readCert(byte[] data, boolean strict) throws CertificateException, ErrorCodeException { X509Certificate cert = readCert(data); if (strict) @@ -584,39 +578,44 @@ public static X509Certificate readCert(byte[] data, boolean strict) throws Certi return cert; } - private static void ensureKeySize(X509Certificate cert) + public static void ensureKeySize(X509Certificate cert) throws ErrorCodeException { if (cert == null) { return; } - if (!log.isErrorEnabled()) - { - return; - } - switch (cert.getPublicKey().getAlgorithm()) { case "RSA": - if (((RSAPublicKey)cert.getPublicKey()).getModulus().bitLength() < MIN_KEY_SIZE_RSA) + if (((RSAPublicKey)cert.getPublicKey()).getModulus().bitLength() < MIN_KEY_SIZE_RSA_SAML) { - log.error("Certificate with subject {} and serial {} does not meet specified minimum RSA key size of {}", - cert.getSubjectDN(), - cert.getSerialNumber(), - MIN_KEY_SIZE_RSA); + String message = String.format("Certificate with subject %s and serial %s does not meet specified minimum RSA key size of %d", + cert.getSubjectX500Principal(), + cert.getSerialNumber(), + MIN_KEY_SIZE_RSA_SAML); + log.warn(message); + throw new ErrorCodeException(ErrorCode.INVALID_CERTIFICATE, message); } break; case "EC": - if (((ECPublicKey)cert.getPublicKey()).getParams() - .getCurve() - .getField() - .getFieldSize() < MIN_KEY_SIZE_EC) + ECParameterSpec ecKeyParams = ((ECPublicKey)cert.getPublicKey()).getParams(); + if (!(ecKeyParams instanceof ECNamedCurveSpec || ecKeyParams instanceof sun.security.util.NamedCurve)) + { + String message = String.format("Certificate with subject %s and serial %s does not use a named curve", + cert.getSubjectX500Principal(), + cert.getSerialNumber()); + log.warn(message); + throw new ErrorCodeException(ErrorCode.INVALID_CERTIFICATE, message); + } + if (ecKeyParams.getCurve().getField().getFieldSize() < MIN_KEY_SIZE_EC_SAML) { - log.error("Certificate with subject {} and serial {} does not meet specified minimum EC key size of {}", - cert.getSubjectDN(), - cert.getSerialNumber(), - MIN_KEY_SIZE_EC); + String message = String.format("Certificate with subject %s and serial %s does not meet specified minimum EC key size of %d", + cert.getSubjectX500Principal(), + cert.getSerialNumber(), + MIN_KEY_SIZE_EC_SAML); + log.warn(message); + throw new ErrorCodeException(ErrorCode.INVALID_CERTIFICATE, message); } break; default: @@ -624,11 +623,11 @@ private static void ensureKeySize(X509Certificate cert) } /** - * Removes "file:" from the input if present. This can be used to use SPRING_CONFIG_LOCATION or - * spring.config.location to specify config locations. + * Removes "file:" from the input if present. This can be used to use SPRING_CONFIG_LOCATION or spring.config.location + * to specify config locations. * - * @param location the string containing the value of SPRING_CONFIG_LOCATION or spring.config.location. Must - * not be null. + * @param location the string containing the value of SPRING_CONFIG_LOCATION or spring.config.location. Must not be + * null. * @return the input string without "file:" if it was present */ public static String prepareSpringConfigLocation(String location) @@ -641,8 +640,8 @@ public static String prepareSpringConfigLocation(String location) } /** - * Returns an initialized {@link BasicParserPool} ready to use, configured with security features preventing - * several XXE attacks. + * Returns an initialized {@link BasicParserPool} ready to use, configured with security features preventing several + * XXE attacks. * * @return the parser pool * @throws ComponentInitializationException @@ -667,8 +666,8 @@ public static BasicParserPool getBasicParserPool() throws ComponentInitializatio } /** - * Returns an initialized {@link DocumentBuilder} ready to use, configured with security features preventing - * several XXE attacks. + * Returns an initialized {@link DocumentBuilder} ready to use, configured with security features preventing several + * XXE attacks. * * @return the document builder * @throws ParserConfigurationException @@ -688,8 +687,8 @@ public static DocumentBuilder getDocumentBuilder() throws ParserConfigurationExc } /** - * Returns an initialized {@link Transformer} ready to use, configured with security features preventing - * several XXE attacks. + * Returns an initialized {@link Transformer} ready to use, configured with security features preventing several XXE + * attacks. * * @return the transformer * @throws TransformerConfigurationException @@ -704,8 +703,8 @@ public static Transformer getTransformer() throws TransformerConfigurationExcept } /** - * Returns an initialized {@link SchemaFactory} ready to use, configured with security features preventing - * several XXE attacks. + * Returns an initialized {@link SchemaFactory} ready to use, configured with security features preventing several XXE + * attacks. * * @return the schema factory * @throws SAXNotRecognizedException @@ -720,15 +719,14 @@ public static SchemaFactory getSchemaFactory() throws SAXNotRecognizedException, } /** - * Returns an initialized {@link Validator} ready to use, configured with security features preventing - * several XXE attacks. + * Returns an initialized {@link Validator} ready to use, configured with security features preventing several XXE + * attacks. * * @return the validator * @throws SAXNotRecognizedException * @throws SAXNotSupportedException */ - public static Validator getValidator(Schema schema) - throws SAXNotRecognizedException, SAXNotSupportedException + public static Validator getValidator(Schema schema) throws SAXNotRecognizedException, SAXNotSupportedException { Validator v = schema.newValidator(); v.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); @@ -737,8 +735,8 @@ public static Validator getValidator(Schema schema) } /** - * Returns an initialized {@link SAXParserFactory} ready to use, configured with security features - * preventing several XXE attacks. + * Returns an initialized {@link SAXParserFactory} ready to use, configured with security features preventing several + * XXE attacks. * * @return the parser factory * @throws SAXNotRecognizedException diff --git a/eidas-demo/README.txt b/eidas-demo/README.txt index 702beaf1..f40b3a4a 100644 --- a/eidas-demo/README.txt +++ b/eidas-demo/README.txt @@ -17,14 +17,5 @@ demo.signature.alias= # Pin for that keystore and entry demo.signature.pin= -# Keystore that is used to decrypt incoming eIDAS responses -demo.decryption.keystore= - -# Alias for that key -demo.decryption.alias= - -# Pin for that keystore and entry -demo.decryption.pin= - # The port the application should listen on. server.port=8080 diff --git a/eidas-demo/pom.xml b/eidas-demo/pom.xml index 23ea6d27..6506319a 100644 --- a/eidas-demo/pom.xml +++ b/eidas-demo/pom.xml @@ -14,7 +14,7 @@ de.governikus.eumw eumw - 3.1.2 + 3.2.0 eidas-demo diff --git a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/Metadata.java b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/Metadata.java index c735b318..dcd0675f 100644 --- a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/Metadata.java +++ b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/Metadata.java @@ -17,8 +17,8 @@ import java.time.temporal.ChronoUnit; import java.util.Arrays; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import javax.xml.transform.TransformerException; import org.opensaml.core.config.InitializationException; diff --git a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewReceiverServlet.java b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewReceiverServlet.java index ae3ed6f8..5df614c0 100644 --- a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewReceiverServlet.java +++ b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewReceiverServlet.java @@ -16,15 +16,15 @@ import java.nio.charset.StandardCharsets; import java.util.stream.Collectors; -import javax.servlet.http.HttpServletRequest; -import javax.xml.bind.DatatypeConverter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.xml.bind.DatatypeConverter; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.MarshallingException; import org.opensaml.core.xml.io.UnmarshallingException; diff --git a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewRequesterServlet.java b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewRequesterServlet.java index 18086e02..53057415 100644 --- a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewRequesterServlet.java +++ b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/NewRequesterServlet.java @@ -13,7 +13,7 @@ import java.util.HashMap; import java.util.Map; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -28,7 +28,7 @@ import de.governikus.eumw.eidasstarterkit.TestCaseEnum; import de.governikus.eumw.eidasstarterkit.person_attributes.EidasPersonAttributes; import lombok.extern.slf4j.Slf4j; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; /** diff --git a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/SamlExampleHelper.java b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/SamlExampleHelper.java index 299e96d0..8f9dfe2b 100644 --- a/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/SamlExampleHelper.java +++ b/eidas-demo/src/main/java/de/governikus/eumw/eidasdemo/SamlExampleHelper.java @@ -12,21 +12,20 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import de.governikus.eumw.eidascommon.Utils; import de.governikus.eumw.eidascommon.Utils.X509KeyPair; import lombok.extern.slf4j.Slf4j; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; /** @@ -147,7 +146,7 @@ private void loadCertificates() demoSignatureCertificate = keyPair.getCert(); demoSignatureKey = keyPair.getKey(); } - catch (IOException | GeneralSecurityException e) + catch (Exception e) { log.error("Cannot load signature keystore", e); } @@ -161,7 +160,7 @@ private void loadCertificates() demoDecryptionKeystorePin.toCharArray(), true); } - catch (IOException | GeneralSecurityException e) + catch (Exception e) { log.error("Cannot load signature keystore", e); } diff --git a/eidas-middleware/pom.xml b/eidas-middleware/pom.xml index 7560175b..6a8c24bf 100644 --- a/eidas-middleware/pom.xml +++ b/eidas-middleware/pom.xml @@ -14,7 +14,7 @@ de.governikus.eumw eumw - 3.1.2 + 3.2.0 eidas-middleware @@ -77,6 +77,11 @@ h2 + + se.swedenconnect.opensaml + opensaml-eidas + + se.swedenconnect.opensaml opensaml-security-ext diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImpl.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImpl.java index ef84ecf3..6ed7b1c5 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImpl.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImpl.java @@ -30,6 +30,7 @@ import de.governikus.eumw.eidasstarterkit.EidasSigner; import de.governikus.eumw.eidasstarterkit.person_attributes.EidasPersonAttributes; import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; +import de.governikus.eumw.poseidas.server.idprovider.config.KeyPair; import de.governikus.eumw.poseidas.server.pki.HSMServiceHolder; import de.governikus.eumw.poseidas.service.MetadataService; import lombok.RequiredArgsConstructor; @@ -130,13 +131,9 @@ private EidasSigner getEidasSigner(EidasMiddlewareConfig eidasMiddlewareConfig) EidasSigner signer; if (hsmServiceHolder.getKeyStore() == null) { - signer = new EidasSigner(true, - configurationService.getKeyPair(eidasMiddlewareConfig.getEidasConfiguration() - .getSignatureKeyPairName()) - .getKey(), - configurationService.getKeyPair(eidasMiddlewareConfig.getEidasConfiguration() - .getSignatureKeyPairName()) - .getCertificate()); + KeyPair signatureKeyPair = configurationService.getSamlKeyPair(eidasMiddlewareConfig.getEidasConfiguration() + .getSignatureKeyPairName()); + signer = new EidasSigner(true, signatureKeyPair.getKey(), signatureKeyPair.getCertificate()); } else { diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/StartUpListener.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/StartUpListener.java index ad107d3e..9bf3f995 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/StartUpListener.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/StartUpListener.java @@ -9,8 +9,8 @@ package de.governikus.eumw.eidasmiddleware; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/RequestReceiver.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/RequestReceiver.java index 08660212..db45ad0c 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/RequestReceiver.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/RequestReceiver.java @@ -15,7 +15,7 @@ import java.util.Arrays; import java.util.Locale; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -167,11 +167,11 @@ private ModelAndView showErrorPage(String errorMessage) } /** - * Show the middleware page where the user can start the AusweisApp2. + * Show the middleware page where the user can start the AusweisApp. * * @param sessionId The sessionId that is returned by * {@link RequestHandler#handleSAMLRequest(String, String, boolean)} - * @param userAgent to redirect the user the correct way to AusweisApp2 + * @param userAgent to redirect the user the correct way to AusweisApp * @return The ModelAndView object that represents the thymeleaf view */ private ModelAndView showMiddlewarePage(String sessionId, String userAgent) diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/ResponseSender.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/ResponseSender.java index ab6c4352..424c9d37 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/ResponseSender.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/ResponseSender.java @@ -10,7 +10,7 @@ package de.governikus.eumw.eidasmiddleware.controller; -import javax.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServlet; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -49,7 +49,7 @@ public ResponseSender(ResponseHandler responseHandler) } /** - * This endpoint is called after the AusweisApp2 has finished the communication with the eID and redirects + * This endpoint is called after the AusweisApp has finished the communication with the eID and redirects * the user's browser to this endpoint */ @GetMapping diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/TcToken.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/TcToken.java index bd4bee20..baa858ad 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/TcToken.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/controller/TcToken.java @@ -14,7 +14,7 @@ import java.nio.charset.StandardCharsets; import java.util.Map.Entry; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/entities/RequestSession.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/entities/RequestSession.java index 0507029b..08eece80 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/entities/RequestSession.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/entities/RequestSession.java @@ -13,12 +13,12 @@ import java.util.HashMap; import java.util.Map; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; import de.governikus.eumw.eidasstarterkit.EidasRequest; import lombok.Getter; diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandler.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandler.java index fc8a5656..78d7de11 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandler.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandler.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.Objects; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import org.apache.commons.lang3.StringUtils; import org.opensaml.core.config.InitializationException; @@ -35,6 +35,7 @@ import org.xml.sax.SAXException; import de.governikus.eumw.eidascommon.ContextPaths; +import de.governikus.eumw.eidascommon.CryptoAlgUtil; import de.governikus.eumw.eidascommon.ErrorCode; import de.governikus.eumw.eidascommon.ErrorCodeException; import de.governikus.eumw.eidascommon.ErrorCodeWithResponseException; @@ -54,7 +55,7 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.xml.BasicParserPool; import net.shibboleth.utilities.java.support.xml.XMLParserException; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; /** @@ -89,9 +90,13 @@ public EidasRequest handleSAMLRedirectRequest(String samlRequest, String relaySt log.trace("Incoming SAML request: {}", new String(samlRequestBytes, StandardCharsets.UTF_8)); // Pre-validate the request - RequestingServiceProvider serviceProvider = preValidateSAMLRequest(samlRequestBytes); + AuthnRequest authnRequest = preValidateSAMLRequest(samlRequestBytes); + + // Verify the signature algorithm is allowed + CryptoAlgUtil.verifySignatureAlgorithm(sigAlg); // Verify the signature of the SAML request + RequestingServiceProvider serviceProvider = getRequestingServiceProvider(authnRequest); HttpRedirectUtils.verifyQueryString(samlRequest, relayState, sigAlg, @@ -137,10 +142,14 @@ public EidasRequest handleSAMLPostRequest(String relayState, String samlRequestB log.trace("Incoming SAML request: {}", new String(samlRequest, StandardCharsets.UTF_8)); // Pre-validate the request - RequestingServiceProvider serviceProvider = preValidateSAMLRequest(samlRequest); + AuthnRequest authnRequest = preValidateSAMLRequest(samlRequest); + + // Verify the hash and signature algorithm are allowed + CryptoAlgUtil.verifyDigestAndSignatureAlgorithm(authnRequest.getSignature()); // Verify the signature and parse the SAML request List authors = new ArrayList<>(); + RequestingServiceProvider serviceProvider = getRequestingServiceProvider(authnRequest); authors.add(serviceProvider.getSignatureCert()); EidasRequest eidasReq = EidasSaml.parseRequest(new ByteArrayInputStream(samlRequest), authors); @@ -216,12 +225,11 @@ else if (eidasRequest.getProviderName() != null) * * No signature validation is performed. * - * @return The service provider that sent this SAML request. + * @return The parsed SAML request. * @throws Exception when any of these checks fail */ - private RequestingServiceProvider preValidateSAMLRequest(byte[] samlRequest) - throws IOException, SAXException, ErrorCodeException, UnmarshallingException, InitializationException, - XMLParserException, ComponentInitializationException + private AuthnRequest preValidateSAMLRequest(byte[] samlRequest) throws IOException, SAXException, ErrorCodeException, + UnmarshallingException, InitializationException, XMLParserException, ComponentInitializationException { try (InputStream is = new ByteArrayInputStream(samlRequest)) { @@ -247,15 +255,20 @@ private RequestingServiceProvider preValidateSAMLRequest(byte[] samlRequest) throw new ErrorCodeException(ErrorCode.DUPLICATE_REQUEST_ID, authnRequestID); } - // Check the AuthnRequest signature - String issuer = Objects.requireNonNull(authnRequest.getIssuer().getDOM()).getTextContent(); - RequestingServiceProvider requestingServiceProvider = configurationService.getProviderByEntityID(issuer); - if (requestingServiceProvider == null) - { - throw new ErrorCodeException(ErrorCode.UNKNOWN_PROVIDER, issuer); - } - return requestingServiceProvider; + return authnRequest; + + } + } + + private RequestingServiceProvider getRequestingServiceProvider(AuthnRequest authnRequest) throws ErrorCodeException + { + String issuer = Objects.requireNonNull(authnRequest.getIssuer().getDOM()).getTextContent(); + RequestingServiceProvider requestingServiceProvider = configurationService.getProviderByEntityID(issuer); + if (requestingServiceProvider == null) + { + throw new ErrorCodeException(ErrorCode.UNKNOWN_PROVIDER, issuer); } + return requestingServiceProvider; } private void postValidateAndSaveSAMLRequest(String relayState, diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandler.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandler.java index 29e33c03..be196c66 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandler.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandler.java @@ -15,16 +15,11 @@ import java.util.List; import java.util.Locale; -import javax.xml.bind.DatatypeConverter; -import javax.xml.transform.TransformerException; +import jakarta.xml.bind.DatatypeConverter; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang3.StringUtils; import org.jmrtd.lds.icao.ICAOCountry; -import org.opensaml.core.config.InitializationException; -import org.opensaml.core.xml.io.MarshallingException; -import org.opensaml.xmlsec.encryption.support.EncryptionException; -import org.opensaml.xmlsec.signature.support.SignatureException; import org.springframework.stereotype.Service; import de.governikus.eumw.eidascommon.Constants; @@ -71,11 +66,10 @@ import de.governikus.eumw.poseidas.server.pki.HSMServiceHolder; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import net.shibboleth.utilities.java.support.xml.XMLParserException; /** - * Handle the incoming redirect from the Ausweisapp2. Check for eID errors or gather the received data from the eID card + * Handle the incoming redirect from the AusweisApp. Check for eID errors or gather the received data from the eID card * and prepare the SAML response. */ @Slf4j @@ -125,7 +119,7 @@ private RequestSession getSAMLReqSessionByRequestId(String requestId) /** * Get the SAML response string for this refID * - * @param refID The refID that was sent from the AusweisApp2 + * @param refID The refID that was sent from the AusweisApp * @return The SAML response, already encrypted if necessary, signed and base64 encoded */ public String getResultForRefID(String refID) @@ -193,7 +187,7 @@ public String prepareSAMLErrorResponse(RequestingServiceProvider reqSP, byte[] eidasResp = rsp.generateErrorRsp(errorCode, msg); return DatatypeConverter.printBase64Binary(eidasResp); } - catch (IOException | GeneralSecurityException | MarshallingException | SignatureException | TransformerException e) + catch (Exception e) { throw new RequestProcessingException(CANNOT_CREATE_SAML_RESPONSE, e); } @@ -210,9 +204,9 @@ private EidasSigner getEidasSigner() throws IOException, GeneralSecurityExceptio log.debug("Cannot prepare key pair for signature creation without configuration"); throw new RequestProcessingException(CANNOT_CREATE_SAML_RESPONSE); } - var signatureKeyPair = configurationService.getKeyPair(optionalConfiguration.get() - .getEidasConfiguration() - .getSignatureKeyPairName()); + var signatureKeyPair = configurationService.getSamlKeyPair(optionalConfiguration.get() + .getEidasConfiguration() + .getSignatureKeyPairName()); signer = new EidasSigner(true, signatureKeyPair.getKey(), signatureKeyPair.getCertificate()); } else @@ -354,8 +348,7 @@ else if (samlReqSession.getRequestedAttributes().get(EidasNaturalPersonAttribute signer); return DatatypeConverter.printBase64Binary(eidasResp); } - catch (IOException | GeneralSecurityException | InitializationException | XMLParserException | EncryptionException - | MarshallingException | SignatureException | TransformerException e) + catch (Exception e) { throw new RequestProcessingException(CANNOT_CREATE_SAML_RESPONSE, e); } @@ -445,8 +438,7 @@ public String prepareDummyResponse(String requestId, TestCaseEnum testCase) signer); return DatatypeConverter.printBase64Binary(eidasResp); } - catch (IOException | GeneralSecurityException | InitializationException | XMLParserException | EncryptionException - | MarshallingException | SignatureException | TransformerException e) + catch (Exception e) { throw new RequestProcessingException(CANNOT_CREATE_SAML_RESPONSE, e); } diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortCreator.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortCreator.java index 1fb5042e..6783d423 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortCreator.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortCreator.java @@ -11,10 +11,13 @@ import java.io.File; import java.io.IOException; +import java.util.Arrays; import org.apache.catalina.connector.Connector; import org.apache.coyote.http11.AbstractHttp11Protocol; import org.apache.coyote.http11.Http11NioProtocol; +import org.apache.tomcat.util.net.SSLHostConfig; +import org.apache.tomcat.util.net.SSLHostConfigCertificate; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; @@ -99,7 +102,13 @@ public class PortCreator @Bean public WebServerFactoryCustomizer servletContainerCustomizer() { - return factory -> factory.addConnectorCustomizers(c -> ((AbstractHttp11Protocol)c.getProtocolHandler()).setSSLHonorCipherOrder(true)); + return factory -> factory.addConnectorCustomizers(connector -> { + if (connector.getProtocolHandler() instanceof AbstractHttp11Protocol httpHandler) + { + Arrays.stream(httpHandler.findSslHostConfigs()) + .forEach(sslHostConfig -> sslHostConfig.setHonorCipherOrder(true)); + } + }); } /** @@ -159,14 +168,27 @@ private void configureSslProtocol(Http11NioProtocol protocol) protocol.setSecure(true); protocol.setPort(adminInterfacePort); File keystoreFile = getSslConnectorKeystoreFile(); - protocol.setKeystoreFile(keystoreFile.getAbsolutePath()); - protocol.setKeystorePass(keystorePassword); - protocol.setKeyAlias(keyAlias); - protocol.setKeyPass(keystorePassword); - protocol.setSslEnabledProtocols(serverSslProtocols); - protocol.setCiphers(serverSslCiphers); - protocol.setSSLHonorCipherOrder(true); + + SSLHostConfig sslHostConfig = new SSLHostConfig(); + + sslHostConfig.setEnabledProtocols(serverSslProtocols.split(",")); + // sslHostConfig.setCiphers(serverSslCiphers); + sslHostConfig.setEnabledCiphers(serverSslCiphers.split(",")); + sslHostConfig.setHonorCipherOrder(true); + + SSLHostConfigCertificate sslHostConfigCertificate = new SSLHostConfigCertificate(sslHostConfig, + SSLHostConfigCertificate.Type.UNDEFINED); + sslHostConfigCertificate.setCertificateKeystoreFile(keystoreFile.getAbsolutePath()); + sslHostConfigCertificate.setCertificateKeystoreType(keystoreType); + sslHostConfigCertificate.setCertificateKeystorePassword(keystorePassword); + sslHostConfigCertificate.setCertificateKeyAlias(keyAlias); + sslHostConfigCertificate.setCertificateKeyPassword(keystorePassword); + + sslHostConfig.addCertificate(sslHostConfigCertificate); + + protocol.addSslHostConfig(sslHostConfig); protocol.setMaxHttpHeaderSize(maxHeaderSize); + } /** diff --git a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortFilter.java b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortFilter.java index 30fe861c..1f259523 100644 --- a/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortFilter.java +++ b/eidas-middleware/src/main/java/de/governikus/eumw/eidasmiddleware/projectconfig/PortFilter.java @@ -11,10 +11,10 @@ import java.io.IOException; -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; diff --git a/eidas-middleware/src/main/resources/i18n/messages_de.properties b/eidas-middleware/src/main/resources/i18n/messages_de.properties index 756b895f..0bfb9a12 100644 --- a/eidas-middleware/src/main/resources/i18n/messages_de.properties +++ b/eidas-middleware/src/main/resources/i18n/messages_de.properties @@ -14,18 +14,18 @@ title.title=Deutsche eIDAS Middleware content.title=Nutzung Ihres deutschen Ausweises an Online-Diensten anderer EU-Mitgliedstaaten content.language=Wählen Sie Ihre Sprache content.requirements.title=Für die Nutzung der Online-Ausweisfunktion benötigen Sie -content.requirements.npa=1. Einen Personalausweis / einen elektronischen Aufenthaltstitel / eine Unionsbürgerkarte +content.requirements.npa=1. Einen Personalausweis oder elektronischen Aufenthaltstitel mit aktivierter Online-Ausweisfunktion oder eine eID-Karte für Unionsbürger content.requirements.npa.hint=mit freigeschalteter Online-Ausweisfunktion und Ihre persönliche PIN -content.requirements.device=2. Ein Kartenlesegerät, iOS- oder Android-Mobilgerät zum direkten Auslesen per NFC -content.requirements.device.hint=Eine Übersicht geeigneter Kartenlesegeräte oder mobiler Geräte finden Sie unter https://www.ausweisapp.bund.de (Kartenlesegerät / Smartphones / Tablets) -content.requirements.app=3. Die AusweisApp2 -content.requirements.app.hint=Um den Vorgang fortzusetzen, muss die AusweisApp2 gestartet sein
Diese können Sie kostenlos hier herunterladen:
Zur Downloadseite +content.requirements.device=2. Ein NFC-fähiges Smartphone oder ein USB-Kartenlesegerät +content.requirements.device.hint=Eine Übersicht geeigneter Kartenlesegeräte oder mobiler Geräte finden Sie unter https://www.ausweisapp.bund.de (Kartenlesegerät / Smartphones / Tablets) +content.requirements.app=3. Die AusweisApp +content.requirements.app.hint=Um den Vorgang fortzusetzen, muss die AusweisApp gestartet sein
Diese können Sie kostenlos hier herunterladen:
Zur Downloadseite content.requirements.app.hint.mobile=Zuerst muss die mobile App installiert werden: -content.help=

ⓘ Woran erkenne ich, ob die Online-Ausweisfunktion freigeschaltet ist?


Die AusweisApp2 teilt Ihnen mit, wenn dies bei Ihnen nicht der Fall sein sollte. Sie können die Online-Ausweisfunktion bei Ihrer für die Ausgabe Ihres Ausweisdokumentes zuständigen Behörde freischalten lassen.

-content.help.link=Nähere Informationen zum Start der AusweisApp2 finden Sie in der Online-Hilfe. +content.help=

ⓘ Woran erkenne ich, ob die Online-Ausweisfunktion freigeschaltet ist?


Die AusweisApp teilt Ihnen mit, wenn dies bei Ihnen nicht der Fall sein sollte. Sie können die Online-Ausweisfunktion bei Ihrer für die Ausgabe Ihres Ausweisdokumentes zuständigen Behörde freischalten lassen.

+content.help.link=Nähere Informationen zum Start der AusweisApp finden Sie in der Online-Hilfe. content.start=Verstanden, jetzt online ausweisen → -content.eid.status.active=Die AusweisApp2 ist gestartet und kann verwendet werden. -content.eid.status.inactive=Leider ist keine AusweisApp2 gestartet oder installiert. Bitte starten Sie diese bevor Sie fortfahren. +content.eid.status.active=Die AusweisApp ist gestartet und kann verwendet werden. +content.eid.status.inactive=Leider ist keine AusweisApp gestartet oder installiert. Bitte starten Sie diese bevor Sie fortfahren. # error error.title=Es ist ein Fehler aufgetreten error.general=Während der Verarbeitung Ihrer Anfrage ist es zu einem Fehler gekommen. Bitte versuchen Sie es erneut.
Falls der Fehler erneut auftritt, wenden Sie sich bitte an ihren Diensteanbieter. @@ -37,7 +37,7 @@ response.continue=Weiter # footer footer.footer=Die eIDAS Middleware wird im Auftrag des BSI bereitgestellt von Governikus KG # images -image.ausweisapp2=Logo AusweisApp2 +image.ausweisapp=Logo AusweisApp image.cr-phone=Logo Kartenleser und Smartphone image.npa-left=Logo Personalausweis image.icon.accept=Grüner Haken diff --git a/eidas-middleware/src/main/resources/i18n/messages_en.properties b/eidas-middleware/src/main/resources/i18n/messages_en.properties index 21338cc3..fa9cee1b 100644 --- a/eidas-middleware/src/main/resources/i18n/messages_en.properties +++ b/eidas-middleware/src/main/resources/i18n/messages_en.properties @@ -17,14 +17,14 @@ content.requirements.npa=1. An identity card / electronic residence permit / eID content.requirements.npa.hint=with enabled online ID function together with your personal PIN content.requirements.device=2. A card reader, Android or iOS device for direct readout via NFC content.requirements.device.hint=An overview of suitable card readers or mobile devices can be found at https://www.ausweisapp.bund.de/en (card reader / smartphones / tablets) -content.requirements.app=3. The AusweisApp2 -content.requirements.app.hint=To continue the identification process the AusweisApp2 must be running
The App can be downloaded for free here:
To download page -content.requirements.app.hint.mobile=First install the AusweisApp2 on your device: -content.help=

ⓘ How can I tell if the online ID function is activated?


The AusweisApp2 will inform you if this is not the case. You can have the online ID function enabled by the authority responsible for issuing your ID document.

-content.help.link=Find further information on starting of AusweisApp2 on the help pages. +content.requirements.app=3. The AusweisApp +content.requirements.app.hint=To continue the identification process the AusweisApp must be running
The App can be downloaded for free here:
To download page +content.requirements.app.hint.mobile=First install the AusweisApp on your device: +content.help=

ⓘ How can I tell if the online ID function is activated?


The AusweisApp will inform you if this is not the case. You can have the online ID function enabled by the authority responsible for issuing your ID document.

+content.help.link=Find further information on starting of AusweisApp on the help pages. content.start=Understood, identify online now → -content.eid.status.active=AusweisApp2 is running and can be used. -content.eid.status.inactive=Unfortunately, AusweisApp2 is not started or installed. Please start it before proceeding. +content.eid.status.active=AusweisApp is running and can be used. +content.eid.status.inactive=Unfortunately, AusweisApp is not started or installed. Please start it before proceeding. # error error.title=An error occurred error.general=There was an error during the processing of your request. Please try again.
In case this error persists contact your local service provider with the information provided below. @@ -36,7 +36,7 @@ response.continue=Continue # footer footer.footer=eIDAS Middleware provided by Governikus KG on behalf of BSI # images -image.ausweisapp2=AusweisApp2 +image.ausweisapp=AusweisApp image.cr-phone=card reader and smartphone image.npa-left=ID card image.icon.accept=Green Tick diff --git a/eidas-middleware/src/main/resources/static/img/logo-ausweisapp2-xl.png b/eidas-middleware/src/main/resources/static/img/logo-ausweisapp-xl.png similarity index 100% rename from eidas-middleware/src/main/resources/static/img/logo-ausweisapp2-xl.png rename to eidas-middleware/src/main/resources/static/img/logo-ausweisapp-xl.png diff --git a/eidas-middleware/src/main/resources/static/img/logo-ausweisapp2.png b/eidas-middleware/src/main/resources/static/img/logo-ausweisapp.png similarity index 100% rename from eidas-middleware/src/main/resources/static/img/logo-ausweisapp2.png rename to eidas-middleware/src/main/resources/static/img/logo-ausweisapp.png diff --git a/eidas-middleware/src/main/resources/static/img/screenshot-aa2.png b/eidas-middleware/src/main/resources/static/img/screenshot-aa2.png deleted file mode 100644 index 592c4d6c271e59a98c99d0bb240484efb3db6815..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61040 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 z zVbX~=EF6~`U5FQT+cyUAG`{9upW`mBlDTsQ>+9I3EI@fgKKag1Za29`{kHxwR=pXy zbRYs$RvAvNKOKYiKfkE=7OAhBm-t&TZk-tqIq8}cI2*5vrWX+hd};1zM5XK%M(4b* znt$zd?Rw@CYDli~m9ELHt;?=7%5p1~e{JAZt-S||hp-3d?g1%-40xz^xxW5($S9z` z>W9%hG8;GFXX@pIwOJ$0>MsFwmJqz#GLLZ&a zrnO3nm#ir(*tho}r}cy`Kf51O_=W%XsQn-%pBqz4J@l+YqSG?22(mX?JtOKcU%@;{ zO7`gVuvTVhO!eG}NbJ4(b-3jr-r;)v?973TJ(`{Ulf90qL#g{~89h%y_t%C$luJ7N zwass>N0$;evSY8*#^$_?0#XZXQ%@1t<4?tOm|pf%X+x|QML=!r)#j7a+ol$X;Fn82 xm4-Z?p!DhCVHpn1r+1yH|37~+UOA1-(h=#&l;qT9E2PZ={|7C~grNWc diff --git a/eidas-middleware/src/main/resources/templates/middleware.html b/eidas-middleware/src/main/resources/templates/middleware.html index 34c579d7..5f16f38a 100644 --- a/eidas-middleware/src/main/resources/templates/middleware.html +++ b/eidas-middleware/src/main/resources/templates/middleware.html @@ -107,16 +107,16 @@

2. A card reader / Android device f

diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/EidasRoundTrip.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/EidasRoundTrip.java index f8433c3d..accc1208 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/EidasRoundTrip.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/EidasRoundTrip.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasmiddleware; @@ -58,7 +57,7 @@ import de.governikus.eumw.eidasstarterkit.person_attributes.natural_persons_attribute.PersonIdentifierAttribute; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.xml.XMLParserException; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; public class EidasRoundTrip @@ -77,9 +76,9 @@ public void setUp() throws InitializationException, NoSuchProviderException try { - keyPair = Utils.readPKCS12(EidasRoundTrip.class.getResourceAsStream("bos-test.saml-sign.p12"), + keyPair = Utils.readPKCS12(EidasRoundTrip.class.getResourceAsStream("bos-test-tctoken.saml-sign.p12"), "123456".toCharArray()); - keyPair2 = Utils.readPKCS12(EidasRoundTrip.class.getResourceAsStream("bos-test.saml-sign.p12"), + keyPair2 = Utils.readPKCS12(EidasRoundTrip.class.getResourceAsStream("bos-test-tctoken.saml-encr.p12"), "123456".toCharArray()); } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException | CertificateException @@ -186,8 +185,8 @@ public void test() throws SAXException } } catch (CertificateEncodingException | InitializationException | IOException | XMLParserException - | UnmarshallingException | MarshallingException | SignatureException - | TransformerFactoryConfigurationError | TransformerException | ComponentInitializationException e) + | UnmarshallingException | MarshallingException | SignatureException | TransformerFactoryConfigurationError + | TransformerException | ComponentInitializationException e) { e.printStackTrace(); } diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImplTest.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImplTest.java index 253d25f3..1dcfb969 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImplTest.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/MetadataServiceImplTest.java @@ -119,7 +119,7 @@ void whenGetMetadataCalledExpectMetadataByteArray() + ContextPaths.METADATA)); Assertions.assertTrue(metadataAsString.contains("2.0")); // part of sig cert - Assertions.assertTrue(metadataAsString.contains("j51v55HpaAA9farLNsxNsmYHKKF8D12gNGHs8XFuVLkG8iHU07RoYJ3h1vrumrd4")); + Assertions.assertTrue(metadataAsString.contains("MIIEsDCCApigAwIBAgIEZXgnNjANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9t")); Assertions.assertFalse(metadataAsString.contains("KeyDescriptor use=\"encryption\"")); } diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/Metadatatest.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/Metadatatest.java index aaac52b3..3883a35e 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/Metadatatest.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/Metadatatest.java @@ -28,7 +28,7 @@ import de.governikus.eumw.eidasstarterkit.EidasOrganisation; import de.governikus.eumw.eidasstarterkit.EidasSaml; import de.governikus.eumw.eidasstarterkit.EidasSigner; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; public class Metadatatest diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/RequestSessionTest.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/RequestSessionTest.java index 0e8012e2..00299ee5 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/RequestSessionTest.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/RequestSessionTest.java @@ -1,24 +1,20 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasmiddleware; import java.util.Collections; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; import org.mockito.Mockito; import de.governikus.eumw.eidasstarterkit.EidasRequest; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; class RequestSessionTest diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerMatrixTest.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerMatrixTest.java index ee1764fa..f1d90664 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerMatrixTest.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerMatrixTest.java @@ -57,7 +57,7 @@ import lombok.AllArgsConstructor; import lombok.ToString; import lombok.extern.slf4j.Slf4j; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; @Slf4j diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerTest.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerTest.java index 56e37e9a..9e34b9bc 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerTest.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHandlerTest.java @@ -24,25 +24,36 @@ import java.security.cert.X509Certificate; import java.util.Base64; import java.util.HashMap; +import java.util.stream.Stream; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactoryConfigurationError; +import org.apache.xml.security.signature.XMLSignature; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.opensaml.core.config.InitializationException; import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.impl.AuthnRequestMarshaller; +import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.opensaml.xmlsec.signature.support.SignatureException; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponentsBuilder; +import org.w3c.dom.Element; import org.xml.sax.SAXParseException; +import de.governikus.eumw.eidascommon.CryptoAlgUtil; import de.governikus.eumw.eidascommon.ErrorCodeException; import de.governikus.eumw.eidascommon.HttpRedirectUtils; import de.governikus.eumw.eidascommon.Utils; @@ -59,8 +70,9 @@ import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; import de.governikus.eumw.utils.key.KeyStoreSupporter; import lombok.Data; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; /** @@ -283,6 +295,62 @@ void testPostInvalidXML() Assertions.assertEquals(RequestHandler.CANNOT_PARSE_SAML_REQUEST, requestProcessingException.getMessage()); } + /** + * MethodSource for testSha1PostRequest() + */ + static Stream testSha1PostRequest() + { + return Stream.of(Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/de/governikus/eumw/eidasmiddleware/bos-test-tctoken.saml-sign.p12", + "bos-test-tctoken.saml-sign"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/de/governikus/eumw/eidasmiddleware/bos-test-tctoken.saml-sign.p12", + "bos-test-tctoken.saml-sign"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1, + SignatureConstants.ALGO_ID_DIGEST_SHA256, + "/de/governikus/eumw/eidasmiddleware/bos-test-tctoken.saml-sign.p12", + "bos-test-tctoken.saml-sign"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/de/governikus/eumw/eidasmiddleware/ecc2.p12", + "ec_nist_p256"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA256, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/de/governikus/eumw/eidasmiddleware/ecc2.p12", + "ec_nist_p256"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1, + SignatureConstants.ALGO_ID_DIGEST_SHA256, + "/de/governikus/eumw/eidasmiddleware/ecc2.p12", + "ec_nist_p256")); + } + + @SneakyThrows + @ParameterizedTest + @MethodSource + void testSha1PostRequest(String signatureAlgorithm, String digestAlgorithm, String keyStorePath, String alias) + { + File keystoreFile = new File(RequestHandlerTest.class.getResource(keyStorePath).toURI()); + KeyStore keyStore = KeyStoreSupporter.readKeyStore(keystoreFile, DEFAULT_PASSWORD); + byte[] sha1SamlRequest = RequestHelper.createSamlPostRequest("http://localhost:8080/eIDASDemoApplication/NewReceiverServlet", + "http://localhost:8080/eIDASDemoApplication/Metadata", + (X509Certificate)keyStore.getCertificate(alias), + (PrivateKey)keyStore.getKey(alias, + DEFAULT_PASSWORD.toCharArray()), + signatureAlgorithm, + digestAlgorithm); + + RequestHandler requestHandler = new RequestHandler(requestSessionRepository, mockConfigurationService); + RequestProcessingException requestProcessingException = Assertions.assertThrows(RequestProcessingException.class, + () -> requestHandler.handleSAMLPostRequest(RELAY_STATE, + Base64.getEncoder() + .encodeToString(sha1SamlRequest))); + ErrorCodeException errorCodeException = (ErrorCodeException)requestProcessingException.getCause(); + Assertions.assertEquals(1, errorCodeException.getDetails().length); + Assertions.assertEquals(CryptoAlgUtil.INVALID_HASH_OR_SIGNATURE_ALGORITHM, errorCodeException.getDetails()[0]); + } + /** * Test that a request with the wrong signature certificate is rejected */ @@ -486,6 +554,28 @@ void testRedirectInvalidBase64() throws URISyntaxException Assertions.assertEquals(RequestHandler.CANNOT_PARSE_SAML_REQUEST, requestProcessingException.getMessage()); } + @SneakyThrows + @ParameterizedTest + @ValueSource(strings = {XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1, XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1}) + void testSha1RedirectRequest(String signatureAlgorithm) + { + RequestHandler requestHandler = new RequestHandler(requestSessionRepository, mockConfigurationService); + AuthnRequest unsignedAuthnRequest = RequestHelper.createUnsignedAuthnRequest("http://localhost:8080/eIDASDemoApplication/NewReceiverServlet", + "http://localhost:8080/eIDASDemoApplication/Metadata"); + AuthnRequestMarshaller arm = new AuthnRequestMarshaller(); + Element element = arm.marshall(unsignedAuthnRequest); + byte[] authnRequestBytes = RequestHelper.marshallAuthnRequest(element); + + RequestProcessingException requestProcessingException = Assertions.assertThrows(RequestProcessingException.class, + () -> requestHandler.handleSAMLRedirectRequest(HttpRedirectUtils.deflate(authnRequestBytes), + RELAY_STATE, + signatureAlgorithm, + null)); + ErrorCodeException errorCodeException = (ErrorCodeException)requestProcessingException.getCause(); + Assertions.assertEquals(1, errorCodeException.getDetails().length); + Assertions.assertEquals(CryptoAlgUtil.INVALID_HASH_OR_SIGNATURE_ALGORITHM, errorCodeException.getDetails()[0]); + } + /** * Create a SAML request that is ready to be sent via Post * diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHelper.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHelper.java new file mode 100644 index 00000000..7a5f183d --- /dev/null +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/RequestHelper.java @@ -0,0 +1,107 @@ +package de.governikus.eumw.eidasmiddleware.handler; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import jakarta.xml.bind.DatatypeConverter; + +import org.opensaml.core.xml.Namespace; +import org.opensaml.saml.common.SAMLObjectContentReference; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.impl.AuthnRequestBuilder; +import org.opensaml.saml.saml2.core.impl.AuthnRequestMarshaller; +import org.opensaml.security.x509.BasicX509Credential; +import org.opensaml.xmlsec.signature.KeyInfo; +import org.opensaml.xmlsec.signature.Signature; +import org.opensaml.xmlsec.signature.X509Data; +import org.opensaml.xmlsec.signature.impl.KeyInfoBuilder; +import org.opensaml.xmlsec.signature.impl.SignatureBuilder; +import org.opensaml.xmlsec.signature.impl.X509CertificateBuilder; +import org.opensaml.xmlsec.signature.impl.X509DataBuilder; +import org.opensaml.xmlsec.signature.support.SignatureConstants; +import org.opensaml.xmlsec.signature.support.Signer; +import org.w3c.dom.Element; + +import de.governikus.eumw.eidascommon.Utils; +import de.governikus.eumw.eidasstarterkit.EidasSaml; +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; +import se.swedenconnect.opensaml.eidas.common.EidasConstants; + + +@UtilityClass +public class RequestHelper { + + @SneakyThrows + public static byte[] createSamlPostRequest(String destination, + String providerName, + X509Certificate cert, + PrivateKey key, + String signatureAlgorithm, + String digestAlgorithm) { + AuthnRequest authnRequest = createUnsignedAuthnRequest(destination, providerName); + + Signature sig = new SignatureBuilder().buildObject(); + BasicX509Credential credential = new BasicX509Credential(cert); + credential.setPrivateKey(key); + sig.setSigningCredential(credential); + sig.setSignatureAlgorithm(signatureAlgorithm); + sig.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + KeyInfo keyInfo = new KeyInfoBuilder().buildObject(); + X509Data x509Data = new X509DataBuilder().buildObject(); + org.opensaml.xmlsec.signature.X509Certificate xmlcert = new X509CertificateBuilder().buildObject(); + xmlcert.setValue(DatatypeConverter.printBase64Binary(cert.getEncoded())); + x509Data.getX509Certificates().add(xmlcert); + keyInfo.getX509Datas().add(x509Data); + sig.setKeyInfo(keyInfo); + authnRequest.setSignature(sig); + ((SAMLObjectContentReference) sig.getContentReferences().get(0)).setDigestAlgorithm(digestAlgorithm); + + + List sigs = new ArrayList<>(); + sigs.add(authnRequest.getSignature()); + AuthnRequestMarshaller arm = new AuthnRequestMarshaller(); + Element all = arm.marshall(authnRequest); + Signer.signObjects(sigs); + + return marshallAuthnRequest(all); + } + + @SneakyThrows + public static byte[] marshallAuthnRequest(Element all) { + Transformer trans = Utils.getTransformer(); + trans.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name()); + try (ByteArrayOutputStream bout = new ByteArrayOutputStream()) { + trans.transform(new DOMSource(all), new StreamResult(bout)); + return bout.toByteArray(); + } + } + + @SneakyThrows + public static AuthnRequest createUnsignedAuthnRequest(String destination, String providerName) { + EidasSaml.init(); + + AuthnRequest authnRequest = new AuthnRequestBuilder().buildObject(); + + authnRequest.setID("_" + UUID.randomUUID()); + authnRequest.setForceAuthn(true); + authnRequest.setIsPassive(false); + authnRequest.getNamespaceManager() + .registerNamespaceDeclaration(new Namespace(EidasConstants.EIDAS_NS, EidasConstants.EIDAS_PREFIX)); + authnRequest.setDestination(destination); + authnRequest.setIssueInstant(Instant.now()); + authnRequest.setProviderName(providerName); + return authnRequest; + } +} diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandlerTest.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandlerTest.java index 1776fe32..829a70ae 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandlerTest.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/handler/ResponseHandlerTest.java @@ -23,7 +23,7 @@ import java.util.Optional; import java.util.stream.Stream; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -351,9 +351,9 @@ private void mockConfigurationServiceForEidasSigner() throws IOException, Genera eidasMiddlewareConfiguration.setEidasConfiguration(new EidasMiddlewareConfig.EidasConfiguration()); eidasMiddlewareConfiguration.getEidasConfiguration().setSignatureKeyPairName("signatureKeystore"); when(mockConfigurationService.getConfiguration()).thenReturn(Optional.of(eidasMiddlewareConfiguration)); - when(mockConfigurationService.getKeyPair(Mockito.anyString())).thenReturn(new KeyPair(signatureKeystore, - "bos-test-tctoken.saml-sign", - DEFAULT_PASSWORD)); + when(mockConfigurationService.getSamlKeyPair(Mockito.anyString())).thenReturn(new KeyPair(signatureKeystore, + "bos-test-tctoken.saml-sign", + DEFAULT_PASSWORD)); } @Test @@ -759,7 +759,7 @@ void testRequestWithTestCaseCancellationByUserReturnsErrorResponse() throws Exce .getValue() .contains("AuthnFailed")); Assertions.assertEquals("Authentication cancelled by user", - result.getOpenSamlResponse().getStatus().getStatusMessage().getMessage()); + result.getOpenSamlResponse().getStatus().getStatusMessage().getValue()); Assertions.assertNull(result.getLoa()); } @@ -789,7 +789,7 @@ void testRequestWithTestCaseWrongSignatureReturnsErrorResponse() throws Exceptio Assertions.assertTrue(result.getOpenSamlResponse().getStatus().getStatusCode().getValue().contains(RESPONDER)); Assertions.assertEquals("An error was reported from eID-Server: http://www.bsi.bund.de/eid/server/2.0/resultminor/getResult#invalidDocument", - result.getOpenSamlResponse().getStatus().getStatusMessage().getMessage()); + result.getOpenSamlResponse().getStatus().getStatusMessage().getValue()); Assertions.assertNull(result.getLoa()); } @@ -819,7 +819,7 @@ void testRequestWithTestCaseUnknownReturnsErrorResponse() throws Exception Assertions.assertTrue(result.getOpenSamlResponse().getStatus().getStatusCode().getValue().contains(RESPONDER)); Assertions.assertEquals("An internal error occurred, see log file of the application server. Details: An unknown error occurred", - result.getOpenSamlResponse().getStatus().getStatusMessage().getMessage()); + result.getOpenSamlResponse().getStatus().getStatusMessage().getValue()); Assertions.assertNull(result.getLoa()); } @@ -851,7 +851,7 @@ void testWhenCvcCheckFailedThenReturnErrorResponse() throws Exception Assertions.assertTrue(result.getOpenSamlResponse().getStatus().getStatusCode().getValue().contains(RESPONDER)); Assertions.assertEquals("There is an error in the configuration of the server, attribute with the value 'false' need to be fixed. CvcCheckResults{cvcPresent=true, cvcValidity=false, cvcUrlMatch=true, cvcTlsMatch=true}", - result.getOpenSamlResponse().getStatus().getStatusMessage().getMessage()); + result.getOpenSamlResponse().getStatus().getStatusMessage().getValue()); Assertions.assertNull(result.getLoa()); } @@ -908,7 +908,7 @@ private void prepareMocks(KeyStore keystore, String alias, String password) when(mockRequestSession.getReqProviderEntityId()).thenReturn(ENTITY_ID); when(mockConfigurationService.getProviderByEntityID(ENTITY_ID)).thenReturn(mockRequestingServiceProvider); when(mockHsmServiceHolder.getKeyStore()).thenReturn(null); - when(mockConfigurationService.getKeyPair(Mockito.anyString())).thenReturn(new KeyPair(keystore, alias, password)); + when(mockConfigurationService.getSamlKeyPair(Mockito.anyString())).thenReturn(new KeyPair(keystore, alias, password)); when(mockRequestingServiceProvider.getAssertionConsumerURL()).thenReturn("consumerUrl"); when(mockConfigurationService.getServerURLWithEidasContextPath()).thenReturn("https://localhost"); when(mockRequestingServiceProvider.getEntityID()).thenReturn(ENTITY_ID); diff --git a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/repositories/RequestSessionTestSetup.java b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/repositories/RequestSessionTestSetup.java index fdea1a8b..63f602bb 100644 --- a/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/repositories/RequestSessionTestSetup.java +++ b/eidas-middleware/src/test/java/de/governikus/eumw/eidasmiddleware/repositories/RequestSessionTestSetup.java @@ -11,7 +11,7 @@ import java.util.Properties; -import javax.persistence.EntityManagerFactory; +import jakarta.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.springframework.context.annotation.Bean; diff --git a/eidas-middleware/src/test/resources/EidasSignerTest_x509.cer b/eidas-middleware/src/test/resources/EidasSignerTest_x509.cer index 9c2b4ca5b2b5760e5691f79b3878b68de94a8ca2..714221054f3699c5bddc0568daaadc1811afbf42 100644 GIT binary patch literal 1688 zcmZuyw+{2@5$yRC?u8$WVkoZon1h%zJLViDCXr8Xo!y;f}8fByW66(q&@ z7biHLA}Sp4gulT*kgh1g%5xl8+8Ue+3u;A3qL0~nz+mhC-Sn-*oCpi-RRlapb*DbX zI_3l0=6S$~P#QW-jv7mXJ%@a7h8(v~xycQ^)4zHrAUfY825*1Ezp?utSO-$*pN#*H zu&$L>2Z+SEZ^>0MoVSJFMm_+9!a@8A&fkCr=HFd5_xa!vI;|320%uigJnxe}KM-Ag zrc{Lh#(wXi@SLr?hsT1ivIvsa*@;mGUTJq)_GsDy|9B|e8V$j%y{|_~GqAdSU%m1C zEIdx3mqAST64k!-VO2DT&gZjnIx35dE`PBf%<}_XCKDH39;#iJs8|RqqH%uN+m6kA zFOvF(cK>MNUyr}48EO-OSBn?(exq&+r~H=hHG){BDi&GR34$o>ujOJx!en8UdLR_7 zUOp$*xo-$|R|L>a8Bfg1&kg{Z*k__Si0elZM$e-eNBQXnOxA4INs~x)f4GF?kW{ek z{5z?$L^cbgm!Sn~3jGaaIQL4}B|mg|=;7rV9fl9m005c6=)K3-<}HqaY@8Nw3VsuC^UUJ5eZCG&79f`)NyuZg)*W zhTMt}`xm}98sfF0#!5F}8dOVko6pv@$98WQUt70I4GoXLH`}@L92_^-?ktt2Eukz5 zDTS*{3vPm!jkKxkv!*q0Uz2toT1n2bs$TNaG#nTVs*>I89Z**wz$DUW8Ad_Z`@*>C z=%m^RV>B0;OT(17GXn-6MEbB#^d;vTKaq%%2Ec$9UZeMx?lUW8Cw&?r4iQxNHdXUu zdqmGKm!zc!-G0_fr`5CJcO}`vS|oXbjn{M4L6cr&ID4zD@W2Kv^iPd*=YKW+lXVXB zD3w3+1V?y51I1-q=7)Zuyi|h^Gcy`@!Z)K{0xUc z;*7^nlLJ+9sV`y}(-5`4+z3cbNE*K{s}X$Do@t?%9*WtSNPHY*7wjK|_9EjA^a6_m z#4h@>zO9?fi%Oq*=?KJ={z6IV3}EWEWI)-QR9>*LcYKa~^Xl(ZF(i+8NEX#XL$Q^wH{a>uaW>D~QZAE45)>GbkvbcfwRj84B+6Lq z(#Gw|g$cPD-Q(dQOkje8HhI8|I5+sb7dyX48%a4S*cADZT#OQ#d@&ZTnR&8vYLv%h zpsyk1XJGaN2NFAtxb98}pJhEZ@?4~M+So|8*}}(?%+}^lir9F=kiBeg{Qbp8v|%8C za-lp#StH2hK5j+vqj78DORb(%Eia2`yfdvJHwuV^_aJj0nNGqB`2<-jx2(LE4uz4Z S#o({Mp#S8IVDSH&J^u!wvme|5 literal 928 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 MgPHTs|Gw@20hL1F;s5{u delta 4078 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 diff --git a/eidas-middleware/src/test/resources/de/governikus/eumw/eidasmiddleware/bos-test-tctoken.saml-sign.p12 b/eidas-middleware/src/test/resources/de/governikus/eumw/eidasmiddleware/bos-test-tctoken.saml-sign.p12 index 62316ac66fcf92e78f01408f8ccbb1a64d648af9..fdc4911ef4b8eef5cd86c3fe31d1d5f1282742ca 100644 GIT binary patch delta 4166 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 LopEdY@7w+#JImZ2 delta 4078 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 diff --git a/eidas-middleware/src/test/resources/eidasmiddlewareProperties/middleware-crypt.jks b/eidas-middleware/src/test/resources/eidasmiddlewareProperties/middleware-crypt.jks index eb4df957710142679ecd426f2976ef12723429dd..7756033110b1a765c0101738bed5f7bda94f957a 100644 GIT binary patch delta 3652 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 y%8MSUuf{&L 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 sXcL)hKkA9g5`Q!2KSHtL!2kdN diff --git a/eidas-starterkit/pom.xml b/eidas-starterkit/pom.xml index cf752a4b..9fa9f8db 100644 --- a/eidas-starterkit/pom.xml +++ b/eidas-starterkit/pom.xml @@ -14,7 +14,7 @@ de.governikus.eumw eumw - 3.1.2 + 3.2.0 eidas-starterkit @@ -26,14 +26,19 @@ eidas-common + + se.swedenconnect.opensaml + opensaml-eidas + + se.swedenconnect.opensaml opensaml-security-ext - se.litsec.eidas - eidas-opensaml4 + org.apache.commons + commons-lang3 @@ -49,6 +54,27 @@ junit junit + test + + + + org.slf4j + slf4j-simple + test
+ + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/sun.security.util=ALL-UNNAMED + + + + + diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasEncrypter.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasEncrypter.java index 0c55127c..07cdf999 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasEncrypter.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasEncrypter.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasstarterkit; @@ -13,6 +12,7 @@ import java.security.KeyException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; +import java.util.Collection; import org.apache.xml.security.algorithms.MessageDigestAlgorithm; import org.opensaml.core.config.ConfigurationService; @@ -22,15 +22,19 @@ import org.opensaml.security.credential.CredentialSupport; import org.opensaml.security.x509.BasicX509Credential; import org.opensaml.xmlsec.EncryptionConfiguration; +import org.opensaml.xmlsec.SecurityConfigurationSupport; +import org.opensaml.xmlsec.agreement.KeyAgreementException; +import org.opensaml.xmlsec.agreement.KeyAgreementParameter; +import org.opensaml.xmlsec.agreement.KeyAgreementParameters; +import org.opensaml.xmlsec.agreement.KeyAgreementProcessor; +import org.opensaml.xmlsec.agreement.KeyAgreementSupport; import org.opensaml.xmlsec.algorithm.AlgorithmSupport; import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters; import org.opensaml.xmlsec.encryption.support.EncryptionConstants; import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters; import org.opensaml.xmlsec.encryption.support.RSAOAEPParameters; import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory; - -import se.swedenconnect.opensaml.xmlsec.config.ExtendedDefaultSecurityConfigurationBootstrap; -import se.swedenconnect.opensaml.xmlsec.encryption.support.ECDHKeyAgreementParameters; +import org.opensaml.xmlsec.keyinfo.impl.KeyAgreementKeyInfoGeneratorFactory; public class EidasEncrypter @@ -41,6 +45,19 @@ public class EidasEncrypter */ Encrypter encrypter; + /** + * Cipher-Algorithm is set to http://www.w3.org/2009/xmlenc11#aes256-gcm + * + * @param includeCert + * @param cert + * @throws NoSuchAlgorithmException + * @throws KeyException + */ + public EidasEncrypter(boolean includeCert, X509Certificate cert) throws NoSuchAlgorithmException, KeyException + { + this(includeCert, cert, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM); + } + /** * Create a XMLCipher Object. * @@ -62,26 +79,19 @@ private EidasEncrypter(boolean includeCert, X509Certificate cert, String cipherA if ("EC".equals(cert.getPublicKey().getAlgorithm())) { - ECDHKeyAgreementParameters ecdhKeyAgreementParameters = new ECDHKeyAgreementParameters(); - ecdhKeyAgreementParameters.setPeerCredential(receiverCredential); - ecdhKeyAgreementParameters.setKeyInfoGenerator(ExtendedDefaultSecurityConfigurationBootstrap.buildDefaultKeyAgreementKeyInfoGeneratorFactory() - .newInstance()); - encrypter = new Encrypter(encParams, ecdhKeyAgreementParameters); + encrypter = new Encrypter(encParams, getKeyEncryptionParameters(cert, true)); } - else { - /** - * key encryption parameters used to set up the {@link #encrypter}, null if encryption is not set. Note - * that the encrypter will ignore these values given to it in the constructor when it encrypts an - * XMLObject. In that case, you have to give these values again to the encrypt method. + * key encryption parameters used to set up the {@link #encrypter}, null if encryption is not set. Note that the + * encrypter will ignore these values given to it in the constructor when it encrypts an XMLObject. In that case, + * you have to give these values again to the encrypt method. */ KeyEncryptionParameters kek = new KeyEncryptionParameters(); kek.setAlgorithm(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP); kek.setEncryptionCredential(receiverCredential); - kek.setRSAOAEPParameters(new RSAOAEPParameters(MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256, null, - null)); + kek.setRSAOAEPParameters(new RSAOAEPParameters(MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256, null, null)); encrypter = new Encrypter(encParams, kek); if (includeCert) { @@ -95,17 +105,79 @@ private EidasEncrypter(boolean includeCert, X509Certificate cert, String cipherA encrypter.setKeyPlacement(KeyPlacement.INLINE); } - /** - * Cipher-Algorithm is set to http://www.w3.org/2009/xmlenc11#aes256-gcm - * - * @param includeCert - * @param cert - * @throws NoSuchAlgorithmException - * @throws KeyException - */ - public EidasEncrypter(boolean includeCert, X509Certificate cert) + private static KeyEncryptionParameters getKeyEncryptionParameters(X509Certificate encryptionCertificate, + boolean includeCert) throws NoSuchAlgorithmException, KeyException { - this(includeCert, cert, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM); + KeyEncryptionParameters kekParameters = new KeyEncryptionParameters(); + String algorithm = encryptionCertificate.getPublicKey().getAlgorithm(); + return switch (algorithm) + { + case "EC" -> + { + prepareForEC(encryptionCertificate, kekParameters); + yield kekParameters; + } + case "RSA" -> + { + prepareForRsa(encryptionCertificate, includeCert, kekParameters); + yield kekParameters; + } + default -> throw new NoSuchAlgorithmException("Not supported or unknown standard algorithm name: " + + encryptionCertificate.getPublicKey().getAlgorithm()); + }; + + } + + private static void prepareForRsa(X509Certificate encryptionCertificate, + boolean includeCert, + KeyEncryptionParameters kekParameters) + { + kekParameters.setAlgorithm(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP); + kekParameters.setEncryptionCredential(CredentialSupport.getSimpleCredential(encryptionCertificate, null)); + kekParameters.setRSAOAEPParameters(new RSAOAEPParameters(EncryptionConstants.ALGO_ID_DIGEST_SHA256, null, null)); + if (includeCert) + { + KeyInfoGeneratorFactory kigf = ConfigurationService.get(EncryptionConfiguration.class) + .getKeyTransportKeyInfoGeneratorManager() + .getDefaultManager() + .getFactory(new BasicX509Credential(encryptionCertificate)); + kekParameters.setKeyInfoGenerator(kigf.newInstance()); + } + } + + private static void prepareForEC(X509Certificate encryptionCertificate, KeyEncryptionParameters kekParameters) + throws KeyException + { + kekParameters.setAlgorithm(EncryptionConstants.ALGO_ID_KEYWRAP_AES256); + Credential keyAgreementCredential = getKeyAgreementCredential(CredentialSupport.getSimpleCredential(encryptionCertificate, + null)); + kekParameters.setEncryptionCredential(keyAgreementCredential); + KeyAgreementKeyInfoGeneratorFactory newKeyInfoGenerator = new KeyAgreementKeyInfoGeneratorFactory(); + kekParameters.setKeyInfoGenerator(newKeyInfoGenerator.newInstance()); + } + + private static Credential getKeyAgreementCredential(Credential credential) throws KeyException + { + try + { + Collection keyAgreementParameterCollection = SecurityConfigurationSupport.getGlobalEncryptionConfiguration() + .getKeyAgreementConfigurations() + .get("EC") + .getParameters(); + if (keyAgreementParameterCollection == null) + { + throw new KeyException("Key agreement parameters are null"); + } + + KeyAgreementParameters keyAgreementParameters = new KeyAgreementParameters(keyAgreementParameterCollection); + KeyAgreementProcessor keyAgreementProcessor = KeyAgreementSupport.getProcessor("http://www.w3.org/2009/xmlenc11#ECDH-ES"); + return keyAgreementProcessor.execute(credential, EncryptionConstants.ALGO_ID_KEYWRAP_AES256, keyAgreementParameters); + + } + catch (KeyAgreementException | KeyException var4) + { + throw new KeyException("Could not generate key agreement credentials", var4); + } } } diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasLoaEnum.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasLoaEnum.java index b2e3e152..5ef9b966 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasLoaEnum.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasLoaEnum.java @@ -1,6 +1,6 @@ package de.governikus.eumw.eidasstarterkit; -import se.litsec.eidas.opensaml.common.EidasConstants; +import se.swedenconnect.opensaml.eidas.common.EidasConstants; public enum EidasLoaEnum diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataNode.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataNode.java index cd1675dd..6fd82aa7 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataNode.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataNode.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasstarterkit; @@ -30,11 +29,9 @@ import org.apache.xml.security.algorithms.MessageDigestAlgorithm; import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.core.config.InitializationException; import org.opensaml.core.xml.Namespace; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.MarshallingException; -import org.opensaml.core.xml.io.Unmarshaller; -import org.opensaml.core.xml.io.UnmarshallerFactory; import org.opensaml.core.xml.io.UnmarshallingException; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.ext.saml2alg.DigestMethod; @@ -88,7 +85,6 @@ import org.opensaml.xmlsec.signature.support.SignatureException; import org.opensaml.xmlsec.signature.support.Signer; import org.w3c.dom.DOMException; -import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -100,13 +96,12 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; -import net.shibboleth.utilities.java.support.xml.BasicParserPool; import net.shibboleth.utilities.java.support.xml.XMLConstants; import net.shibboleth.utilities.java.support.xml.XMLParserException; -import se.litsec.eidas.opensaml.common.EidasConstants; -import se.litsec.eidas.opensaml.ext.SPType; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; -import se.litsec.eidas.opensaml.ext.impl.SPTypeBuilder; +import se.swedenconnect.opensaml.eidas.common.EidasConstants; +import se.swedenconnect.opensaml.eidas.ext.SPType; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.impl.SPTypeBuilder; /** @@ -182,22 +177,19 @@ public class EidasMetadataNode } } - byte[] generate(EidasSigner signer) throws CertificateEncodingException, MarshallingException, - SignatureException, TransformerException, IOException + byte[] generate(EidasSigner signer) + throws CertificateEncodingException, MarshallingException, SignatureException, TransformerException, IOException { EntityDescriptor entityDescriptor = new EntityDescriptorBuilder().buildObject(); entityDescriptor.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(EidasConstants.EIDAS_NS, - EidasConstants.EIDAS_PREFIX)); + .registerNamespaceDeclaration(new Namespace(EidasConstants.EIDAS_NS, EidasConstants.EIDAS_PREFIX)); entityDescriptor.getNamespaceManager() .registerNamespaceDeclaration(new Namespace(SAMLConstants.SAML20ALG_NS, SAMLConstants.SAML20ALG_PREFIX)); entityDescriptor.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(XMLConstants.XSD_NS, - XMLConstants.XSD_PREFIX)); + .registerNamespaceDeclaration(new Namespace(XMLConstants.XSD_NS, XMLConstants.XSD_PREFIX)); entityDescriptor.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(XMLConstants.XSI_NS, - XMLConstants.XSI_PREFIX)); + .registerNamespaceDeclaration(new Namespace(XMLConstants.XSI_NS, XMLConstants.XSI_PREFIX)); entityDescriptor.setID(id); entityDescriptor.setEntityID(entityId); entityDescriptor.setValidUntil(validUntil); @@ -372,15 +364,10 @@ byte[] generate(EidasSigner signer) throws CertificateEncodingException, Marshal */ static EidasMetadataNode parse(InputStream is, X509Certificate signer, boolean continueOnInvalidSig) throws XMLParserException, UnmarshallingException, CertificateException, ErrorCodeException, - ComponentInitializationException + ComponentInitializationException, InitializationException { EidasMetadataNode eidasMetadataNode = new EidasMetadataNode(); - BasicParserPool ppMgr = Utils.getBasicParserPool(); - Document inCommonMDDoc = ppMgr.parse(is); - Element metadataRoot = inCommonMDDoc.getDocumentElement(); - UnmarshallerFactory unmarshallerFactory = XMLObjectProviderRegistrySupport.getUnmarshallerFactory(); - Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(metadataRoot); - EntityDescriptor metaData = (EntityDescriptor)unmarshaller.unmarshall(metadataRoot); + EntityDescriptor metaData = EidasSaml.unmarshalMetadata(is); Signature sig = metaData.getSignature(); if (sig == null) diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataService.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataService.java index 316a3076..8ed4f710 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataService.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasMetadataService.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasstarterkit; @@ -31,12 +30,10 @@ import org.apache.xml.security.algorithms.MessageDigestAlgorithm; import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.core.config.InitializationException; import org.opensaml.core.xml.Namespace; import org.opensaml.core.xml.XMLObject; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.MarshallingException; -import org.opensaml.core.xml.io.Unmarshaller; -import org.opensaml.core.xml.io.UnmarshallerFactory; import org.opensaml.core.xml.io.UnmarshallingException; import org.opensaml.core.xml.schema.XSAny; import org.opensaml.core.xml.schema.XSString; @@ -99,7 +96,6 @@ import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.opensaml.xmlsec.signature.support.SignatureException; import org.opensaml.xmlsec.signature.support.Signer; -import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -112,12 +108,11 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; -import net.shibboleth.utilities.java.support.xml.BasicParserPool; import net.shibboleth.utilities.java.support.xml.XMLConstants; import net.shibboleth.utilities.java.support.xml.XMLParserException; -import se.litsec.eidas.opensaml.common.EidasConstants; -import se.litsec.eidas.opensaml.ext.NodeCountry; -import se.litsec.eidas.opensaml.ext.impl.NodeCountryBuilder; +import se.swedenconnect.opensaml.eidas.common.EidasConstants; +import se.swedenconnect.opensaml.eidas.ext.NodeCountry; +import se.swedenconnect.opensaml.eidas.ext.impl.NodeCountryBuilder; /** @@ -224,23 +219,19 @@ byte[] generate(EidasSigner signer) throws CertificateEncodingException, IOExcep { EntityDescriptor entityDescriptor = new EntityDescriptorBuilder().buildObject(); entityDescriptor.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(SAMLConstants.SAML20_NS, - SAMLConstants.SAML20_PREFIX)); + .registerNamespaceDeclaration(new Namespace(SAMLConstants.SAML20_NS, SAMLConstants.SAML20_PREFIX)); entityDescriptor.getNamespaceManager() .registerNamespaceDeclaration(new Namespace(SAMLConstants.SAML20ALG_NS, SAMLConstants.SAML20ALG_PREFIX)); entityDescriptor.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(XMLConstants.XSD_NS, - XMLConstants.XSD_PREFIX)); + .registerNamespaceDeclaration(new Namespace(XMLConstants.XSD_NS, XMLConstants.XSD_PREFIX)); entityDescriptor.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(XMLConstants.XSI_NS, - XMLConstants.XSI_PREFIX)); + .registerNamespaceDeclaration(new Namespace(XMLConstants.XSI_NS, XMLConstants.XSI_PREFIX)); entityDescriptor.getNamespaceManager() .registerNamespaceDeclaration(new Namespace(SignatureConstants.XMLSIG_NS, SignatureConstants.XMLSIG_PREFIX)); entityDescriptor.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(EidasConstants.EIDAS_NS, - EidasConstants.EIDAS_PREFIX)); + .registerNamespaceDeclaration(new Namespace(EidasConstants.EIDAS_NS, EidasConstants.EIDAS_PREFIX)); entityDescriptor.setID(id); entityDescriptor.setEntityID(entityId); entityDescriptor.setValidUntil(validUntil); @@ -459,20 +450,14 @@ byte[] generate(EidasSigner signer) throws CertificateEncodingException, IOExcep return result; } - static EidasMetadataService parse(InputStream is) - throws XMLParserException, UnmarshallingException, CertificateException, ComponentInitializationException + static EidasMetadataService parse(InputStream is) throws XMLParserException, UnmarshallingException, + CertificateException, ComponentInitializationException, InitializationException, ErrorCodeException { EidasMetadataService eidasMetadataService = new EidasMetadataService(); - BasicParserPool ppMgr = Utils.getBasicParserPool(); - Document inCommonMDDoc = ppMgr.parse(is); - Element metadataRoot = inCommonMDDoc.getDocumentElement(); - UnmarshallerFactory unmarshallerFactory = XMLObjectProviderRegistrySupport.getUnmarshallerFactory(); - Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(metadataRoot); - EntityDescriptor metaData = (EntityDescriptor)unmarshaller.unmarshall(metadataRoot); + EntityDescriptor metaData = EidasSaml.unmarshalMetadata(is); eidasMetadataService.setSupportContact(unmarshalContactPerson(metaData.getContactPersons(), "support")); - eidasMetadataService.setTechnicalContact(unmarshalContactPerson(metaData.getContactPersons(), - "technical")); + eidasMetadataService.setTechnicalContact(unmarshalContactPerson(metaData.getContactPersons(), "technical")); eidasMetadataService.setOrganisation(unmarshalOrganisation(metaData.getOrganization())); eidasMetadataService.setId(metaData.getID()); eidasMetadataService.setEntityId(metaData.getEntityID()); @@ -574,11 +559,11 @@ private static EidasContactPerson unmarshalContactPerson(List cps { for ( ContactPerson cp : cps ) { - String company = cp.getCompany().getName(); - String givenName = cp.getGivenName().getName(); - String surName = cp.getSurName().getName(); - String tel = cp.getTelephoneNumbers().get(0).getNumber(); - String email = cp.getEmailAddresses().get(0).getAddress(); + String company = cp.getCompany().getValue(); + String givenName = cp.getGivenName().getValue(); + String surName = cp.getSurName().getValue(); + String tel = cp.getTelephoneNumbers().get(0).getValue(); + String email = cp.getEmailAddresses().get(0).getURI(); String type = cp.getType().toString(); EidasContactPerson ecp = new EidasContactPerson(company, givenName, surName, tel, email, type); if (type != null && (type).equalsIgnoreCase(contactType)) @@ -593,7 +578,7 @@ private static EidasOrganisation unmarshalOrganisation(Organization org) { String displayName = org.getDisplayNames().get(0).getValue(); String name = org.getOrganizationNames().get(0).getValue(); - String url = org.getURLs().get(0).getValue(); + String url = org.getURLs().get(0).getURI(); String langId = org.getDisplayNames().get(0).getXMLLang(); return new EidasOrganisation(name, displayName, url, langId); } @@ -606,7 +591,7 @@ private static EidasOrganisation unmarshalOrganisation(Organization org) * @throws CertificateException */ static X509Certificate getFirstCertFromKeyDescriptor(KeyDescriptor keyDescriptor) - throws CertificateException + throws CertificateException, ErrorCodeException { X509Certificate cert = null; if (keyDescriptor.getKeyInfo() != null && !keyDescriptor.getKeyInfo().getX509Datas().isEmpty()) diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasNaturalPersonAttributes.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasNaturalPersonAttributes.java index 33c0f966..eafc5495 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasNaturalPersonAttributes.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasNaturalPersonAttributes.java @@ -27,15 +27,15 @@ import de.governikus.eumw.eidasstarterkit.person_attributes.natural_persons_attribute.PlaceOfBirthAttribute; import lombok.AllArgsConstructor; import lombok.Getter; -import se.litsec.eidas.opensaml.ext.attributes.AttributeConstants; -import se.litsec.eidas.opensaml.ext.attributes.BirthNameType; -import se.litsec.eidas.opensaml.ext.attributes.CurrentAddressType; -import se.litsec.eidas.opensaml.ext.attributes.CurrentFamilyNameType; -import se.litsec.eidas.opensaml.ext.attributes.CurrentGivenNameType; -import se.litsec.eidas.opensaml.ext.attributes.DateOfBirthType; -import se.litsec.eidas.opensaml.ext.attributes.GenderType; -import se.litsec.eidas.opensaml.ext.attributes.PersonIdentifierType; -import se.litsec.eidas.opensaml.ext.attributes.PlaceOfBirthType; +import se.swedenconnect.opensaml.eidas.ext.attributes.AttributeConstants; +import se.swedenconnect.opensaml.eidas.ext.attributes.BirthNameType; +import se.swedenconnect.opensaml.eidas.ext.attributes.CurrentAddressType; +import se.swedenconnect.opensaml.eidas.ext.attributes.CurrentFamilyNameType; +import se.swedenconnect.opensaml.eidas.ext.attributes.CurrentGivenNameType; +import se.swedenconnect.opensaml.eidas.ext.attributes.DateOfBirthType; +import se.swedenconnect.opensaml.eidas.ext.attributes.GenderType; +import se.swedenconnect.opensaml.eidas.ext.attributes.PersonIdentifierType; +import se.swedenconnect.opensaml.eidas.ext.attributes.PlaceOfBirthType; @AllArgsConstructor diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasRequest.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasRequest.java index 9b9cab4f..e2768f5a 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasRequest.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasRequest.java @@ -78,12 +78,12 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.xml.BasicParserPool; import net.shibboleth.utilities.java.support.xml.XMLParserException; -import se.litsec.eidas.opensaml.common.EidasConstants; -import se.litsec.eidas.opensaml.ext.RequestedAttribute; -import se.litsec.eidas.opensaml.ext.SPType; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; -import se.litsec.eidas.opensaml.ext.impl.RequestedAttributeBuilder; -import se.litsec.eidas.opensaml.ext.impl.SPTypeBuilder; +import se.swedenconnect.opensaml.eidas.common.EidasConstants; +import se.swedenconnect.opensaml.eidas.ext.RequestedAttribute; +import se.swedenconnect.opensaml.eidas.ext.SPType; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.impl.RequestedAttributeBuilder; +import se.swedenconnect.opensaml.eidas.ext.impl.SPTypeBuilder; @@ -279,7 +279,7 @@ byte[] generate(Map requestedAttributes) throws { Scoping scoping = new ScopingBuilder().buildObject(); RequesterID requesterID = new RequesterIDBuilder().buildObject(); - requesterID.setRequesterID(requesterId); + requesterID.setURI(requesterId); scoping.getRequesterIDs().add(requesterID); authnRequest.setScoping(scoping); } @@ -451,7 +451,7 @@ private static void setRequesterIdOrProviderName(EidasRequest eidasReq) throws E if (isRequesterIdPresent(eidasReq)) { - eidasReq.requesterId = eidasReq.authnRequest.getScoping().getRequesterIDs().get(0).getRequesterID(); + eidasReq.requesterId = eidasReq.authnRequest.getScoping().getRequesterIDs().get(0).getURI(); } if (isProviderNamePresent(eidasReq)) { diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasResponse.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasResponse.java index 69d2399b..e49867d9 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasResponse.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasResponse.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasstarterkit; @@ -101,8 +100,8 @@ import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.xml.BasicParserPool; import net.shibboleth.utilities.java.support.xml.XMLParserException; -import se.litsec.eidas.opensaml.common.EidasConstants; -import se.litsec.eidas.opensaml.ext.attributes.CurrentAddressType; +import se.swedenconnect.opensaml.eidas.common.EidasConstants; +import se.swedenconnect.opensaml.eidas.ext.attributes.CurrentAddressType; import se.swedenconnect.opensaml.xmlsec.encryption.support.DecryptionUtils; @@ -123,24 +122,18 @@ public class EidasResponse errorCodeToSamlStatus.put(ErrorCode.UNSIGNED_ASSERTIONCONSUMER_URL, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.INVALID_SESSION_ID, Collections.singletonList(StatusCode.REQUESTER)); - errorCodeToSamlStatus.put(ErrorCode.TOO_MANY_OPEN_SESSIONS, - Collections.singletonList(StatusCode.REQUESTER)); + errorCodeToSamlStatus.put(ErrorCode.TOO_MANY_OPEN_SESSIONS, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.MISSING_REQUEST_ID, Collections.singletonList(StatusCode.REQUESTER)); - errorCodeToSamlStatus.put(ErrorCode.SIGNATURE_CHECK_FAILED, - Collections.singletonList(StatusCode.REQUESTER)); + errorCodeToSamlStatus.put(ErrorCode.SIGNATURE_CHECK_FAILED, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.SIGNATURE_MISSING, Collections.singletonList(StatusCode.REQUESTER)); - errorCodeToSamlStatus.put(ErrorCode.ILLEGAL_REQUEST_SYNTAX, - Collections.singletonList(StatusCode.REQUESTER)); + errorCodeToSamlStatus.put(ErrorCode.ILLEGAL_REQUEST_SYNTAX, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.AUTHORIZATION_FAILED, Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); - errorCodeToSamlStatus.put(ErrorCode.AUTHORIZATION_UNFINISHED, - Collections.singletonList(StatusCode.REQUESTER)); + errorCodeToSamlStatus.put(ErrorCode.AUTHORIZATION_UNFINISHED, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.UNKNOWN_PROVIDER, Arrays.asList(StatusCode.RESPONDER, StatusCode.REQUEST_UNSUPPORTED)); - errorCodeToSamlStatus.put(ErrorCode.ILLEGAL_CONFIGURATION, - Collections.singletonList(StatusCode.RESPONDER)); - errorCodeToSamlStatus.put(ErrorCode.CANNOT_ACCESS_CREDENTIALS, - Collections.singletonList(StatusCode.RESPONDER)); + errorCodeToSamlStatus.put(ErrorCode.ILLEGAL_CONFIGURATION, Collections.singletonList(StatusCode.RESPONDER)); + errorCodeToSamlStatus.put(ErrorCode.CANNOT_ACCESS_CREDENTIALS, Collections.singletonList(StatusCode.RESPONDER)); errorCodeToSamlStatus.put(ErrorCode.INVALID_CERTIFICATE, Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); errorCodeToSamlStatus.put(ErrorCode.ILLEGAL_ACCESS_METHOD, @@ -154,29 +147,21 @@ public class EidasResponse errorCodeToSamlStatus.put(ErrorCode.UNEXPECTED_EVENT, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.OUTDATED_REQUEST, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.REQUEST_FROM_FUTURE, Collections.singletonList(StatusCode.REQUESTER)); - errorCodeToSamlStatus.put(ErrorCode.DUPLICATE_REQUEST_ID, - Collections.singletonList(StatusCode.REQUESTER)); + errorCodeToSamlStatus.put(ErrorCode.DUPLICATE_REQUEST_ID, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.EID_ERROR, Collections.singletonList(StatusCode.RESPONDER)); - errorCodeToSamlStatus.put(ErrorCode.ECARD_ERROR, - Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); - errorCodeToSamlStatus.put(ErrorCode.EID_MISSING_TERMINAL_RIGHTS, - Collections.singletonList(StatusCode.RESPONDER)); - errorCodeToSamlStatus.put(ErrorCode.EID_MISSING_ARGUMENT, - Collections.singletonList(StatusCode.RESPONDER)); - errorCodeToSamlStatus.put(ErrorCode.PASSWORD_EXPIRED, - Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); - errorCodeToSamlStatus.put(ErrorCode.PASSWORD_LOCKED, - Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); + errorCodeToSamlStatus.put(ErrorCode.ECARD_ERROR, Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); + errorCodeToSamlStatus.put(ErrorCode.EID_MISSING_TERMINAL_RIGHTS, Collections.singletonList(StatusCode.RESPONDER)); + errorCodeToSamlStatus.put(ErrorCode.EID_MISSING_ARGUMENT, Collections.singletonList(StatusCode.RESPONDER)); + errorCodeToSamlStatus.put(ErrorCode.PASSWORD_EXPIRED, Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); + errorCodeToSamlStatus.put(ErrorCode.PASSWORD_LOCKED, Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); errorCodeToSamlStatus.put(ErrorCode.CANNOT_DECRYPT, Collections.singletonList(StatusCode.REQUESTER)); errorCodeToSamlStatus.put(ErrorCode.ILLEGAL_PSK, Collections.singletonList(StatusCode.REQUESTER)); - errorCodeToSamlStatus.put(ErrorCode.CLIENT_ERROR, - Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); + errorCodeToSamlStatus.put(ErrorCode.CLIENT_ERROR, Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); errorCodeToSamlStatus.put(ErrorCode.PROXY_COUNT_EXCEEDED, Arrays.asList(StatusCode.RESPONDER, StatusCode.PROXY_COUNT_EXCEEDED)); errorCodeToSamlStatus.put(ErrorCode.NO_SUPPORTED_IDP, Arrays.asList(StatusCode.RESPONDER, StatusCode.NO_SUPPORTED_IDP)); - errorCodeToSamlStatus.put(ErrorCode.REQUEST_DENIED, - Arrays.asList(StatusCode.RESPONDER, StatusCode.REQUEST_DENIED)); + errorCodeToSamlStatus.put(ErrorCode.REQUEST_DENIED, Arrays.asList(StatusCode.RESPONDER, StatusCode.REQUEST_DENIED)); errorCodeToSamlStatus.put(ErrorCode.CANCELLATION_BY_USER, Arrays.asList(StatusCode.RESPONDER, StatusCode.AUTHN_FAILED)); errorCodeToSamlStatus.put(ErrorCode.INVALID_NAME_ID_TYPE, @@ -317,8 +302,7 @@ private static void processSAMLResponse(EidasResponse eidasResp, if (code == null) { code = ErrorCode.INTERNAL_ERROR; - throw new ErrorCodeException(code, - "Unkown statuscode " + resp.getStatus().getStatusCode().getValue()); + throw new ErrorCodeException(code, "Unkown statuscode " + resp.getStatus().getStatusCode().getValue()); } // Error response, so un-encrypted assertion! for ( Assertion assertion : resp.getAssertions() ) @@ -347,11 +331,7 @@ private static void processAssertions(EidasResponse eidasResp, private static void setLevelOfAssuranceFromAssertion(EidasResponse eidasResp, Assertion assertion) { - String loa = assertion.getAuthnStatements() - .get(0) - .getAuthnContext() - .getAuthnContextClassRef() - .getURI(); + String loa = assertion.getAuthnStatements().get(0).getAuthnContext().getAuthnContextClassRef().getURI(); EidasLoaEnum loaEnum = EidasLoaEnum.parse(loa); eidasResp.setLoa(loaEnum); } @@ -368,21 +348,18 @@ private static void processAttributes(EidasResponse eidasResp, AttributeStatemen EidasPersonAttributes personAttributes = getEidasPersonAttributes(att); EidasAttribute eidasAttribute = personAttributes.getInstance(); XMLObject attributeValue = att.getAttributeValues().get(0); - if (eidasAttribute instanceof AbstractNonLatinScriptAttribute) + if (eidasAttribute instanceof AbstractNonLatinScriptAttribute attribute) { - AbstractNonLatinScriptAttribute attribute = (AbstractNonLatinScriptAttribute)eidasAttribute; attribute.setValue(attributeValue.getDOM().getTextContent()); if (att.getAttributeValues().size() == 2) { attribute.setNonLatinScript(att.getAttributeValues().get(1).getDOM().getTextContent()); } } - else if (eidasAttribute instanceof CurrentAddressAttribute - && attributeValue instanceof CurrentAddressType) + else if (eidasAttribute instanceof CurrentAddressAttribute currentAddressAttribute + && attributeValue instanceof CurrentAddressType currentAddressType) { - CurrentAddressAttribute attribute = (CurrentAddressAttribute)eidasAttribute; - CurrentAddressType cat = (CurrentAddressType)attributeValue; - attribute.setFromCurrentAddressType(cat); + currentAddressAttribute.setFromCurrentAddressType(currentAddressType); } else { @@ -435,8 +412,7 @@ else if (type == EidasNameIdType.TRANSIENT) } } - private static List collectDecryptedAssertions(Response resp, Decrypter decr) - throws ErrorCodeException + private static List collectDecryptedAssertions(Response resp, Decrypter decr) throws ErrorCodeException { List assertions = new ArrayList<>(); @@ -504,24 +480,21 @@ private static String getAudience(Response resp) throws ErrorCodeException .getAudienceRestrictions() .stream() .findFirst() - .orElseThrow(() -> new ErrorCodeException(ErrorCode.ERROR, - "Missing AudienceRestrictions in response.")) + .orElseThrow(() -> new ErrorCodeException(ErrorCode.ERROR, "Missing AudienceRestrictions in response.")) .getAudiences() .stream() .findFirst() .orElseThrow(() -> new ErrorCodeException(ErrorCode.ERROR, "Missing Audiences in response.")) - .getAudienceURI(); + .getURI(); } - private static void checkSignature(Signature sig, List trustedAnchorList) - throws ErrorCodeException + private static void checkSignature(Signature sig, List trustedAnchorList) throws ErrorCodeException { if (sig == null) { throw new ErrorCodeException(ErrorCode.SIGNATURE_CHECK_FAILED); } - XMLSignatureHandler.checkSignature(sig, - trustedAnchorList.toArray(new X509Certificate[trustedAnchorList.size()])); + XMLSignatureHandler.checkSignature(sig, trustedAnchorList.toArray(new X509Certificate[0])); } private static ErrorCode findErrorCode(String s) @@ -536,9 +509,8 @@ private static ErrorCode findErrorCode(String s) return null; } - public byte[] generateErrorRsp(ErrorCode code, String... msg) - throws IOException, CertificateEncodingException, MarshallingException, SignatureException, - TransformerFactoryConfigurationError, TransformerException + public byte[] generateErrorRsp(ErrorCode code, String... msg) throws IOException, CertificateEncodingException, + MarshallingException, SignatureException, TransformerFactoryConfigurationError, TransformerException { Response response = new ResponseBuilder().buildObject(); response.setDestination(destination); @@ -577,8 +549,7 @@ byte[] generate() throws XMLParserException, IOException, CertificateEncodingExc Assertion assertion = new AssertionBuilder().buildObject(); assertion.getNamespaceManager() - .registerNamespaceDeclaration(new Namespace(EidasConstants.EIDAS_NP_NS, - EidasConstants.EIDAS_NP_PREFIX)); + .registerNamespaceDeclaration(new Namespace(EidasConstants.EIDAS_NP_NS, EidasConstants.EIDAS_NP_PREFIX)); assertion.setIssueInstant(now); assertion.setID("_" + Utils.generateUniqueID()); @@ -617,8 +588,7 @@ private byte[] samlToByteArray(Response response, List signatures) throws IOException, TransformerException, MarshallingException, SignatureException { - Marshaller rm = XMLObjectProviderRegistrySupport.getMarshallerFactory() - .getMarshaller(response.getElementQName()); + Marshaller rm = XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(response.getElementQName()); Element all = rm.marshall(response); Signer.signObjects(signatures); diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSaml.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSaml.java index 61dd8cc5..149b308f 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSaml.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSaml.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasstarterkit; @@ -29,9 +28,14 @@ import org.opensaml.core.config.InitializationException; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.Unmarshaller; +import org.opensaml.core.xml.io.UnmarshallerFactory; import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.xmlsec.encryption.support.EncryptionException; import org.opensaml.xmlsec.signature.support.SignatureException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import org.xml.sax.SAXException; import de.governikus.eumw.eidascommon.ErrorCodeException; @@ -41,15 +45,16 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import net.shibboleth.utilities.java.support.xml.BasicParserPool; import net.shibboleth.utilities.java.support.xml.XMLParserException; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; import se.swedenconnect.opensaml.OpenSAMLInitializer; import se.swedenconnect.opensaml.OpenSAMLSecurityExtensionConfig; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; /** - * Put all method together for creating, validating and parsing of saml messages and make it easy. Using the - * methods of this class will init opensaml automatically + * Put all method together for creating, validating and parsing of saml messages and make it easy. Using the methods of + * this class will init opensaml automatically * * @author hohnholt */ @@ -108,12 +113,12 @@ public static byte[] createRequest(String issuer, SPTypeEnumeration sectorType, EidasNameIdType nameIdPolicy, EidasLoaEnum loa) - throws InitializationException, CertificateEncodingException, IOException, MarshallingException, - SignatureException, TransformerFactoryConfigurationError, TransformerException + throws InitializationException, CertificateEncodingException, IOException, MarshallingException, SignatureException, + TransformerFactoryConfigurationError, TransformerException { init(); - EidasRequest eidasRequest = new EidasRequest(destination, sectorType, nameIdPolicy, loa, issuer, - providerName, requesterId, signer); + EidasRequest eidasRequest = new EidasRequest(destination, sectorType, nameIdPolicy, loa, issuer, providerName, + requesterId, signer); return eidasRequest.generate(requestedAttributes); } @@ -124,8 +129,8 @@ public static byte[] createRequest(String issuer, SPTypeEnumeration sectorType, EidasNameIdType nameIdPolicy, EidasLoaEnum loa) - throws InitializationException, CertificateEncodingException, IOException, MarshallingException, - SignatureException, TransformerFactoryConfigurationError, TransformerException + throws InitializationException, CertificateEncodingException, IOException, MarshallingException, SignatureException, + TransformerFactoryConfigurationError, TransformerException { init(); EidasRequest eidasRequest = new EidasRequest(destination, sectorType, nameIdPolicy, loa, issuer, @@ -147,8 +152,8 @@ public static byte[] createRequest(String issuer, * {@link EidasLoaEnum#LOA_HIGH}. * @param testCase the enum of the test case for the eIDAS-Request. Can be null. * @return the eIDAS-Request as a byte array. - * @see EidasSaml#createRequest(String, String, EidasSigner, Map, SPTypeEnumeration, EidasNameIdType, - * EidasLoaEnum) create a request without a test case. + * @see EidasSaml#createRequest(String, String, EidasSigner, Map, SPTypeEnumeration, EidasNameIdType, EidasLoaEnum) + * create a request without a test case. **/ public static byte[] createRequest(String issuer, String destination, @@ -158,8 +163,8 @@ public static byte[] createRequest(String issuer, EidasNameIdType nameIdPolicy, EidasLoaEnum loa, TestCaseEnum testCase) - throws InitializationException, CertificateEncodingException, IOException, MarshallingException, - SignatureException, TransformerFactoryConfigurationError, TransformerException + throws InitializationException, CertificateEncodingException, IOException, MarshallingException, SignatureException, + TransformerFactoryConfigurationError, TransformerException { init(); EidasRequest eidasRequest = new EidasRequest(destination, sectorType, nameIdPolicy, loa, issuer, @@ -197,9 +202,8 @@ public static EidasRequest parseRequest(InputStream is) throws InitializationExc * @throws InitializationException * @throws ComponentInitializationException */ - public static EidasRequest parseRequest(InputStream is, List authors) - throws InitializationException, XMLParserException, UnmarshallingException, ErrorCodeException, - ComponentInitializationException + public static EidasRequest parseRequest(InputStream is, List authors) throws InitializationException, + XMLParserException, UnmarshallingException, ErrorCodeException, ComponentInitializationException { init(); return EidasRequest.parse(is, authors); @@ -251,13 +255,12 @@ public static byte[] createResponse(List att, String inResponseTo, EidasEncrypter encrypter, EidasSigner signer) - throws InitializationException, CertificateEncodingException, XMLParserException, IOException, - EncryptionException, MarshallingException, SignatureException, TransformerFactoryConfigurationError, - TransformerException + throws InitializationException, CertificateEncodingException, XMLParserException, IOException, EncryptionException, + MarshallingException, SignatureException, TransformerFactoryConfigurationError, TransformerException { init(); - EidasResponse response = new EidasResponse(att, destination, recipient, nameid, inResponseTo, issuer, loa, - signer, encrypter); + EidasResponse response = new EidasResponse(att, destination, recipient, nameid, inResponseTo, issuer, loa, signer, + encrypter); return response.generate(); } @@ -332,11 +335,10 @@ public static byte[] createMetaDataService(String id, TransformerFactoryConfigurationError, TransformerException, InitializationException { init(); - EidasMetadataService meta = new EidasMetadataService(id, entityId, validUntil, sigCert, encCert, - organisation, technicalcontact, supportContact, - postEndpoint, redirectEndpoint, attributes, - supportedNameIdTypes, middlewareVersion, doSign, - requesterIdFlag, countryCode); + EidasMetadataService meta = new EidasMetadataService(id, entityId, validUntil, sigCert, encCert, organisation, + technicalcontact, supportContact, postEndpoint, + redirectEndpoint, attributes, supportedNameIdTypes, + middlewareVersion, doSign, requesterIdFlag, countryCode); return meta.generate(signer); } @@ -350,8 +352,8 @@ public static byte[] createMetaDataService(String id, * @throws IOException * @throws ComponentInitializationException */ - static EidasMetadataService parseMetaDataService(InputStream is) throws CertificateException, - XMLParserException, UnmarshallingException, InitializationException, ComponentInitializationException + static EidasMetadataService parseMetaDataService(InputStream is) throws CertificateException, XMLParserException, + UnmarshallingException, InitializationException, ComponentInitializationException, ErrorCodeException { init(); return EidasMetadataService.parse(is); @@ -388,8 +390,8 @@ public static byte[] createMetaDataNode(String id, SPTypeEnumeration spType, List supportedNameIdTypes, EidasSigner signer) - throws InitializationException, CertificateEncodingException, IOException, MarshallingException, - SignatureException, TransformerException + throws InitializationException, CertificateEncodingException, IOException, MarshallingException, SignatureException, + TransformerException { init(); EidasMetadataNode meta = new EidasMetadataNode(id, entityId, validUntil, sigCert, encCert, organisation, @@ -445,9 +447,8 @@ public static EidasMetadataNode parseMetaDataNode(InputStream is, } /** - * Validates a saml message with the saml-schema-protocol-2_0.xsd, saml-schema-assertion-2_0.xsd, - * xenc-schema.xsd, xmldsig-core-schema.xsd,NaturalPersonShema.xsd If the message is not valid a - * SAXException will be thrown + * Validates a saml message with the saml-schema-protocol-2_0.xsd, saml-schema-assertion-2_0.xsd, xenc-schema.xsd, + * xmldsig-core-schema.xsd,NaturalPersonShema.xsd If the message is not valid a SAXException will be thrown * * @param is the saml message as stream * @param resetStreamAfterValidation if u like to parse the given stream later u have to reset the stream @@ -475,4 +476,25 @@ public static void validateXMLRequest(InputStream is, boolean resetStreamAfterVa } } + /** + * Unmarshal a SAML metadata document from an input stream + * + * @param is The input stream of the SAML metadata document + * @return The unmarshalled metadata + * @throws ComponentInitializationException + * @throws XMLParserException + * @throws UnmarshallingException + */ + public static EntityDescriptor unmarshalMetadata(InputStream is) + throws ComponentInitializationException, XMLParserException, UnmarshallingException, InitializationException + { + init(); + + BasicParserPool ppMgr = Utils.getBasicParserPool(); + Document inCommonMDDoc = ppMgr.parse(is); + Element metadataRoot = inCommonMDDoc.getDocumentElement(); + UnmarshallerFactory unmarshallerFactory = XMLObjectProviderRegistrySupport.getUnmarshallerFactory(); + Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(metadataRoot); + return (EntityDescriptor)unmarshaller.unmarshall(metadataRoot); + } } diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSigner.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSigner.java index e51ccb18..dbc7246d 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSigner.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/EidasSigner.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.eidasstarterkit; @@ -17,6 +16,8 @@ import java.security.UnrecoverableKeyException; import java.security.cert.X509Certificate; +import de.governikus.eumw.eidascommon.ErrorCodeException; +import de.governikus.eumw.eidascommon.Utils; import de.governikus.eumw.eidasstarterkit.XMLSignatureHandler.SigEntryType; import lombok.Getter; @@ -28,7 +29,7 @@ public class EidasSigner { - private static final String SAML_SIGNING = "samlsigning"; + public static final String SAML_SIGNING = "samlsigning"; private static final String DIGEST_DEFAULT = "SHA256"; @@ -52,12 +53,20 @@ public class EidasSigner */ private final SigEntryType sigType; - private EidasSigner(boolean includeCert, PrivateKey key, X509Certificate cert, String digestAlg) + public EidasSigner(boolean includeCert, PrivateKey key, X509Certificate cert, String digestAlg) { if (key == null || cert == null || digestAlg == null) { throw new IllegalArgumentException("must specify all arguments when setting a signer"); } + try + { + Utils.ensureKeySize(cert); + } + catch (ErrorCodeException e) + { + throw new IllegalArgumentException("Cannot create the eidas signer, invalid credential used", e); + } sigType = includeCert ? XMLSignatureHandler.SigEntryType.CERTIFICATE : XMLSignatureHandler.SigEntryType.ISSUERSERIAL; sigKey = key; @@ -66,10 +75,10 @@ private EidasSigner(boolean includeCert, PrivateKey key, X509Certificate cert, S } /** - * Create a XMLSigner Object the sign algo will be http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1 if - * using a cert if a RSA Key or http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256 if using a cert with a - * EC key. The canonicalization algorithm is set to http://www.w3.org/2001/10/xml-exc-c14n# and the digest - * algorithm to http://www.w3.org/2001/04/xmlenc#sha256 + * Create a XMLSigner Object the sign algo will be http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1 if using a + * cert if a RSA Key or http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256 if using a cert with a EC key. The + * canonicalization algorithm is set to http://www.w3.org/2001/10/xml-exc-c14n# and the digest algorithm to + * http://www.w3.org/2001/04/xmlenc#sha256 * * @param includeCert * @param key @@ -85,10 +94,8 @@ public EidasSigner(boolean includeCert, PrivateKey key, X509Certificate cert) this(true, key, cert); } - public EidasSigner(KeyStore keyStore) - throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException + public EidasSigner(KeyStore keyStore) throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException { - this(true, (PrivateKey)keyStore.getKey(SAML_SIGNING, null), - (X509Certificate)keyStore.getCertificate(SAML_SIGNING)); + this(true, (PrivateKey)keyStore.getKey(SAML_SIGNING, null), (X509Certificate)keyStore.getCertificate(SAML_SIGNING)); } } diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/SPTypeHelper.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/SPTypeHelper.java index d04608bb..9f69246e 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/SPTypeHelper.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/SPTypeHelper.java @@ -10,12 +10,12 @@ package de.governikus.eumw.eidasstarterkit; -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; /** @@ -43,7 +43,7 @@ else if (StringUtils.equalsIgnoreCase(SPTypeEnumeration.PUBLIC.getValue(), spTyp else { throw new IllegalArgumentException("Received Invalid SPType: " - + StringEscapeUtils.escapeHtml(spTypeString)); + + StringEscapeUtils.escapeHtml4(spTypeString)); } } } diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/XMLSignatureHandler.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/XMLSignatureHandler.java index 849ee0bf..acec8330 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/XMLSignatureHandler.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/XMLSignatureHandler.java @@ -14,7 +14,7 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import org.opensaml.saml.common.SAMLObjectContentReference; import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/additional/attributes/NationalityType.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/additional/attributes/NationalityType.java index efb09c5c..693a8a2b 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/additional/attributes/NationalityType.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/additional/attributes/NationalityType.java @@ -4,8 +4,8 @@ import org.opensaml.core.xml.schema.XSString; -import se.litsec.eidas.opensaml.common.EidasConstants; -import se.litsec.eidas.opensaml.ext.attributes.EidasAttributeValueType; +import se.swedenconnect.opensaml.eidas.common.EidasConstants; +import se.swedenconnect.opensaml.eidas.ext.attributes.EidasAttributeValueType; /** diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/AbstractNonLatinScriptAttribute.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/AbstractNonLatinScriptAttribute.java index fa119bb0..b6b4f650 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/AbstractNonLatinScriptAttribute.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/AbstractNonLatinScriptAttribute.java @@ -19,7 +19,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import se.litsec.eidas.opensaml.ext.attributes.TransliterationStringType; +import se.swedenconnect.opensaml.eidas.ext.attributes.TransliterationStringType; @Getter diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/CurrentAddressAttribute.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/CurrentAddressAttribute.java index 6de8c455..757fad74 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/CurrentAddressAttribute.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/CurrentAddressAttribute.java @@ -20,8 +20,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import se.litsec.eidas.opensaml.ext.attributes.CurrentAddressType; -import se.litsec.eidas.opensaml.ext.attributes.impl.CurrentAddressTypeBuilder; +import se.swedenconnect.opensaml.eidas.ext.attributes.CurrentAddressType; +import se.swedenconnect.opensaml.eidas.ext.attributes.impl.CurrentAddressTypeBuilder; @Getter diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/GenderAttribute.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/GenderAttribute.java index a2ae3ecf..ce83dfbb 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/GenderAttribute.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/GenderAttribute.java @@ -19,8 +19,8 @@ import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import se.litsec.eidas.opensaml.ext.attributes.GenderTypeEnumeration; -import se.litsec.eidas.opensaml.ext.attributes.impl.GenderTypeBuilder; +import se.swedenconnect.opensaml.eidas.ext.attributes.GenderTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.attributes.impl.GenderTypeBuilder; @NoArgsConstructor @@ -53,7 +53,7 @@ public String getValue() public Attribute generate() { Attribute attr = super.generate(); - se.litsec.eidas.opensaml.ext.attributes.GenderType gt = new GenderTypeBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, + se.swedenconnect.opensaml.eidas.ext.attributes.GenderType gt = new GenderTypeBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, type().getQName()); gt.setGender(GenderTypeEnumeration.fromValue(getValue())); attr.getAttributeValues().add(gt); diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/NationalityAttribute.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/NationalityAttribute.java index 4a09be97..3153505b 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/NationalityAttribute.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/NationalityAttribute.java @@ -9,7 +9,7 @@ import de.governikus.eumw.eidasstarterkit.person_attributes.AbstractEidasAttribute; import de.governikus.eumw.eidasstarterkit.person_attributes.EidasPersonAttributes; import lombok.NoArgsConstructor; -import se.litsec.eidas.opensaml.ext.attributes.AttributeConstants; +import se.swedenconnect.opensaml.eidas.ext.attributes.AttributeConstants; /** diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PersonIdentifierAttribute.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PersonIdentifierAttribute.java index 046e85b1..b87e5218 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PersonIdentifierAttribute.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PersonIdentifierAttribute.java @@ -17,8 +17,8 @@ import de.governikus.eumw.eidasstarterkit.person_attributes.AbstractEidasAttribute; import de.governikus.eumw.eidasstarterkit.person_attributes.EidasPersonAttributes; import lombok.NoArgsConstructor; -import se.litsec.eidas.opensaml.ext.attributes.PersonIdentifierType; -import se.litsec.eidas.opensaml.ext.attributes.impl.PersonIdentifierTypeBuilder; +import se.swedenconnect.opensaml.eidas.ext.attributes.PersonIdentifierType; +import se.swedenconnect.opensaml.eidas.ext.attributes.impl.PersonIdentifierTypeBuilder; @NoArgsConstructor diff --git a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PlaceOfBirthAttribute.java b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PlaceOfBirthAttribute.java index 29a41d22..4c15e668 100644 --- a/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PlaceOfBirthAttribute.java +++ b/eidas-starterkit/src/main/java/de/governikus/eumw/eidasstarterkit/person_attributes/natural_persons_attribute/PlaceOfBirthAttribute.java @@ -17,8 +17,8 @@ import de.governikus.eumw.eidasstarterkit.person_attributes.AbstractEidasAttribute; import de.governikus.eumw.eidasstarterkit.person_attributes.EidasPersonAttributes; import lombok.NoArgsConstructor; -import se.litsec.eidas.opensaml.ext.attributes.PlaceOfBirthType; -import se.litsec.eidas.opensaml.ext.attributes.impl.PlaceOfBirthTypeBuilder; +import se.swedenconnect.opensaml.eidas.ext.attributes.PlaceOfBirthType; +import se.swedenconnect.opensaml.eidas.ext.attributes.impl.PlaceOfBirthTypeBuilder; @NoArgsConstructor diff --git a/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasMetadataServiceTest.java b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasMetadataServiceTest.java index 4bad3361..ba9e7cfe 100644 --- a/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasMetadataServiceTest.java +++ b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasMetadataServiceTest.java @@ -40,7 +40,7 @@ import de.governikus.eumw.eidascommon.Utils; import de.governikus.eumw.eidascommon.Utils.X509KeyPair; import de.governikus.eumw.eidasstarterkit.person_attributes.EidasPersonAttributes; -import net.shibboleth.utilities.java.support.logic.ConstraintViolationException; +import net.shibboleth.shared.logic.ConstraintViolationException; import net.shibboleth.utilities.java.support.xml.BasicParserPool; @@ -105,7 +105,7 @@ void manipulatedMetadataThrowsSignatureException() throws Exception EidasSigner signer = new EidasSigner(keyPair.getKey(), keyPair.getCert()); byte[] metadataByteArray = eidasMetadataService.generate(signer); String metadataString = new String(metadataByteArray); - String manipulatedString = metadataString.replace("entityID", "newEntityID"); + String manipulatedString = metadataString.replace("\"entityID\"", "\"newEntityID\""); byte[] manipulatedStringBytes = manipulatedString.getBytes(StandardCharsets.UTF_8); EntityDescriptor entityDescriptor = getEntityDescriptor(manipulatedStringBytes); SAMLSignatureProfileValidator samlSignatureProfileValidator = new SAMLSignatureProfileValidator(); diff --git a/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasRequestTest.java b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasRequestTest.java index 6214e431..d8b48770 100644 --- a/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasRequestTest.java +++ b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasRequestTest.java @@ -29,7 +29,7 @@ import de.governikus.eumw.eidascommon.Utils; import de.governikus.eumw.eidasstarterkit.person_attributes.EidasPersonAttributes; import de.governikus.eumw.utils.key.KeyStoreSupporter; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; class EidasRequestTest @@ -42,7 +42,7 @@ void setUp() throws Exception { EidasSaml.init(); authors = new ArrayList<>(); - X509Certificate cert = Utils.readCert(TestEidasSaml.class.getResourceAsStream("/EidasSignerTest_x509.cer")); + X509Certificate cert = Utils.readCert(TestEidasSaml.class.getResourceAsStream("/EidasSignerTest_x509-old.cer")); authors.add(cert); } @@ -113,8 +113,8 @@ void parseSamlRequestWithUnsupportedNameIDPolicyType() throws Exception void createSignedRequest() throws Exception { // Prepare request - KeyStore keyStore = KeyStoreSupporter.readKeyStore(EidasRequestTest.class.getResourceAsStream("/eidassignertest.jks"), - KeyStoreSupporter.KeyStoreType.JKS, + KeyStore keyStore = KeyStoreSupporter.readKeyStore(EidasRequestTest.class.getResourceAsStream("/eidassignertest.p12"), + KeyStoreSupporter.KeyStoreType.PKCS12, "123456"); EidasSigner signer = new EidasSigner(true, (PrivateKey)keyStore.getKey("eidassignertest", "123456".toCharArray()), (X509Certificate)keyStore.getCertificate("eidassignertest")); @@ -148,8 +148,8 @@ void createSignedRequest() throws Exception void createUnsignedRequest() throws Exception { // Prepare request - KeyStore keyStore = KeyStoreSupporter.readKeyStore(EidasRequestTest.class.getResourceAsStream("/eidassignertest.jks"), - KeyStoreSupporter.KeyStoreType.JKS, + KeyStore keyStore = KeyStoreSupporter.readKeyStore(EidasRequestTest.class.getResourceAsStream("/eidassignertest.p12"), + KeyStoreSupporter.KeyStoreType.PKCS12, "123456"); HashMap reqAtt = new HashMap<>(); reqAtt.put(EidasNaturalPersonAttributes.FIRST_NAME, true); diff --git a/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasSignerTest.java b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasSignerTest.java new file mode 100644 index 00000000..47cd7408 --- /dev/null +++ b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/EidasSignerTest.java @@ -0,0 +1,51 @@ +package de.governikus.eumw.eidasstarterkit; + +import java.io.InputStream; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import de.governikus.eumw.utils.key.KeyStoreSupporter; +import lombok.SneakyThrows; + + +class EidasSignerTest +{ + + @SneakyThrows + @ParameterizedTest + @CsvSource(value = {"/rsa-2048.p12:rsa-2048:Certificate is not valid for that purpose because of reason Certificate with subject CN=rsa-2048 and serial 1702297893 does not meet specified minimum RSA key size of 3072.", + "/secp224r1.p12:secp224r1:Certificate is not valid for that purpose because of reason Certificate with subject CN=secp224r1 and serial 691177073619503856166633885441189605629960653141 does not meet specified minimum EC key size of 256.", + "/brainpoolP512r1-explicit.p12:brainpoolP512r1:Certificate is not valid for that purpose because of reason Certificate with subject CN=BPR-CSCA, OU=Autent, O=Governikus, L=Bremen, C=DE and serial 30727073461927801660542095644293943332594583035 does not use a named curve."}, delimiter = ':') + void testInvalidKeys(String keyStorePath, String alias, String expectedErrorMessage) + { + InputStream keyStoreInputStream = EidasSignerTest.class.getResourceAsStream(keyStorePath); + KeyStore keyStore = KeyStoreSupporter.readKeyStore(keyStoreInputStream, + KeyStoreSupporter.KeyStoreType.PKCS12, + "123456"); + + IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class, + () -> new EidasSigner((PrivateKey)keyStore.getKey(alias, + "123456".toCharArray()), + (X509Certificate)keyStore.getCertificate(alias))); + Assertions.assertEquals(expectedErrorMessage, illegalArgumentException.getCause().getMessage()); + } + + @SneakyThrows + @ParameterizedTest + @CsvSource({"/eidassignertest_ec.p12,eumw-test-ec", "/eidassignertest.p12,eidassignertest"}) + void testValidKeys(String keyStorePath, String alias) + { + InputStream keyStoreInputStream = EidasSignerTest.class.getResourceAsStream(keyStorePath); + KeyStore keyStore = KeyStoreSupporter.readKeyStore(keyStoreInputStream, + KeyStoreSupporter.KeyStoreType.PKCS12, + "123456"); + Assertions.assertDoesNotThrow(() -> new EidasSigner((PrivateKey)keyStore.getKey(alias, "123456".toCharArray()), + (X509Certificate)keyStore.getCertificate(alias))); + } + +} diff --git a/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/TestEidasSaml.java b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/TestEidasSaml.java index f8a7fb66..b48ff08f 100644 --- a/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/TestEidasSaml.java +++ b/eidas-starterkit/src/test/java/de/governikus/eumw/eidasstarterkit/TestEidasSaml.java @@ -22,7 +22,6 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.text.ParseException; import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; @@ -161,7 +160,7 @@ void requestFromXMLfile() throws IOException, CertificateException, XMLParserExc String issuer = "https://test/"; String destination = "test destination"; String providerName = "test providername"; - X509Certificate cert = Utils.readCert(TestEidasSaml.class.getResourceAsStream("/EidasSignerTest_x509.cer")); + X509Certificate cert = Utils.readCert(TestEidasSaml.class.getResourceAsStream("/EidasSignerTest_x509-old.cer")); List authors = new ArrayList<>(); authors.add(cert); @@ -277,7 +276,7 @@ void createParseErrorResponse() throws CertificateException, IOException, Unreco void createParseMetaDataService() throws IOException, XMLParserException, UnmarshallingException, MarshallingException, SignatureException, TransformerFactoryConfigurationError, TransformerException, CertificateException, UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, - NoSuchProviderException, ParseException, InitializationException, ComponentInitializationException + NoSuchProviderException, InitializationException, ComponentInitializationException, ErrorCodeException { String id = "test id"; String entityId = "test entityid"; @@ -444,7 +443,7 @@ private void setRequesterId(AuthnRequest authnRequest) { Scoping scoping = new ScopingBuilder().buildObject(); RequesterID requesterID = new RequesterIDBuilder().buildObject(); - requesterID.setRequesterID("test requesterId"); + requesterID.setURI("test requesterId"); scoping.getRequesterIDs().add(requesterID); authnRequest.setScoping(scoping); } diff --git a/eidas-starterkit/src/test/resources/EidasSignerTest_x509-old.cer b/eidas-starterkit/src/test/resources/EidasSignerTest_x509-old.cer new file mode 100644 index 0000000000000000000000000000000000000000..9c2b4ca5b2b5760e5691f79b3878b68de94a8ca2 GIT binary patch literal 928 zcmXqLVxD8r#MH8YnTe5!i6!iU(K`cPHcqWJkGAi;jEvl@3N@8(vW_n&~QAlcW2~36^rwkWP8E%|1%os8Ta^k#(W(Gz^W`>4_ zMuwJA;=IPl+(GE#CPpRXU}a=wU~XdMXE11D6-tA`+L)SX3zOV{`W3#joiz>>`U&t zeu$}DeE;F&06#&K2YXh!ToTb-u*A*()srW;*RMTl6{u@qaJ+)Me9b|ra3*F(21eu% z0wz3Q2r)7Q32f)u#dq$;ZJwnvp_3hjjC@wkoSw7msi;+CU(A>4q`v8*(=;DlXZx z;fg`h?}(FC-{n@!Vmu{T1Z zyLb7l-RWfBU0|)EtDO@6I4*oLpJ3A+JF~eSXU^uxF1aKA&|UKx)s{)mEJ4v~x3Ey}8kQsQiWCBr#adG@O2H$HDmBFcBC2M4U$`9kYVU`X46 z+UJj1-z=E1v?!V_&T6`Z;f}8fByW66(q&@ z7biHLA}Sp4gulT*kgh1g%5xl8+8Ue+3u;A3qL0~nz+mhC-Sn-*oCpi-RRlapb*DbX zI_3l0=6S$~P#QW-jv7mXJ%@a7h8(v~xycQ^)4zHrAUfY825*1Ezp?utSO-$*pN#*H zu&$L>2Z+SEZ^>0MoVSJFMm_+9!a@8A&fkCr=HFd5_xa!vI;|320%uigJnxe}KM-Ag zrc{Lh#(wXi@SLr?hsT1ivIvsa*@;mGUTJq)_GsDy|9B|e8V$j%y{|_~GqAdSU%m1C zEIdx3mqAST64k!-VO2DT&gZjnIx35dE`PBf%<}_XCKDH39;#iJs8|RqqH%uN+m6kA zFOvF(cK>MNUyr}48EO-OSBn?(exq&+r~H=hHG){BDi&GR34$o>ujOJx!en8UdLR_7 zUOp$*xo-$|R|L>a8Bfg1&kg{Z*k__Si0elZM$e-eNBQXnOxA4INs~x)f4GF?kW{ek z{5z?$L^cbgm!Sn~3jGaaIQL4}B|mg|=;7rV9fl9m005c6=)K3-<}HqaY@8Nw3VsuC^UUJ5eZCG&79f`)NyuZg)*W zhTMt}`xm}98sfF0#!5F}8dOVko6pv@$98WQUt70I4GoXLH`}@L92_^-?ktt2Eukz5 zDTS*{3vPm!jkKxkv!*q0Uz2toT1n2bs$TNaG#nTVs*>I89Z**wz$DUW8Ad_Z`@*>C z=%m^RV>B0;OT(17GXn-6MEbB#^d;vTKaq%%2Ec$9UZeMx?lUW8Cw&?r4iQxNHdXUu zdqmGKm!zc!-G0_fr`5CJcO}`vS|oXbjn{M4L6cr&ID4zD@W2Kv^iPd*=YKW+lXVXB zD3w3+1V?y51I1-q=7)Zuyi|h^Gcy`@!Z)K{0xUc z;*7^nlLJ+9sV`y}(-5`4+z3cbNE*K{s}X$Do@t?%9*WtSNPHY*7wjK|_9EjA^a6_m z#4h@>zO9?fi%Oq*=?KJ={z6IV3}EWEWI)-QR9>*LcYKa~^Xl(ZF(i+8NEX#XL$Q^wH{a>uaW>D~QZAE45)>GbkvbcfwRj84B+6Lq z(#Gw|g$cPD-Q(dQOkje8HhI8|I5+sb7dyX48%a4S*cADZT#OQ#d@&ZTnR&8vYLv%h zpsyk1XJGaN2NFAtxb98}pJhEZ@?4~M+So|8*}}(?%+}^lir9F=kiBeg{Qbp8v|%8C za-lp#StH2hK5j+vqj78DORb(%Eia2`yfdvJHwuV^_aJj0nNGqB`2<-jx2(LE4uz4Z S#o({Mp#S8IVDSH&J^u!wvme|5 literal 928 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 literal 0 HcmV?d00001 diff --git a/eidas-starterkit/src/test/resources/eidassignertest.jks b/eidas-starterkit/src/test/resources/eidassignertest.jks deleted file mode 100644 index 51e9895b097ba04b9014c80f7574b76a4c7e241f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2289 zcmd6odo*+=! z`JM^z3MPAz$Xjz;X;a2D2m}Vu6uwQgAVgpv1mFWuJO}^)gZLd?^;(W7fpifhddMWI*!QKvSF>UD_>38O=0t?-TE~_gS z7BsLzeiZTZ@e!F_?Id07L!yMlV1`>aeurJoaG!m6A0g8VZRu=+?bly%d}JTwnXjxcJG-{UOKBluoaTwpcKf)oaCA5#AmG)G#Ax<9FGv zgZIwP_(rmP`=V&;3u&eCG>IQYRV53crE_sNsJTOWad7)N|M6>0%nAIdngMu_`pj)s z`>%~QAHBpEuhav%90)#mG>`4{1TnNS)N<#`!IBS4Vsik@5XFu<*cV+6VDDHs&`XsZq1aQ_nS{O_il@c-PWwb zxu;}-QVj445687<=p8Y#;&WZHS}BeD=2P}kKN+Mn*YkvWo1KXdsK$`IeMY z7zCdaA_X^M*?gm*%!ww;6h=LU(SI5_CggCD&%~c#5^!WdAbQW8!UZRy;$=I@XV`tV)^UctZver|*uvV*{ta_l`d#OKV6w!WyNECumf=@=lW@HP2^;5b z-h7ZWr|5VQ!3ilVmSQEuAgKKo$bsH8MZ77%H9KongESe+FZdY|y6SWMeUy$|apa0* zcs$O8$JvyIWK>KR7pe?O5jWzm7{+l5VO;$vSrl|G>C|fv6}7k9ah;FSJBu%pP{C$O@^rZE;t- zK+(7p@{8jz-mhP}Uk8}IdzV0Fj$WLvf6U8+!;G+_6yO)S72fR3l=G5Og?3G*GCfln3jf(uh>ap_CH8xriO zu7%bHfq3)L6y97kg(oJTmj~eC;j{0-enZ0{{3xm!bqx*xFfa%moq~a(`60X~`5+=Z zM#dNk^v-|Gw(Ua3|MaZw@1C{W>e>Gj=wFGzUkU85g!f+rjTDDt_M@@b{TK`ei_s>C z!*PGw|KP?HK<>|2x1J6!1rP$EDS!YE1pq))%a!2MUxe>Jc2*;XkGVhF&0(rN-lJ+h zYVBS%B&G>c?sD1G?`yc8khct5qs;S~=b1oY2R7meHV^jx^$~X06~$LPzbq zUUC4vI;Hu%&VsOkl8Ae~zS8;ag25 zl+_ZW-&UES>iQcQ?}{m!yFdNvsNEcaUq;SsLYX7R3r-gcKaH`DTO%|-HCWb4^+jLH-q0uidz{1L&?sDMa1wg=`32hzTRzd&>zoS;5UaS7EV+ddu=U!vl#yhZNNIdAhJpJERLDC?ECq-!kiZ z?Jv#zC_Z+u5Sd&W)*i0yKGi!`U+v*oonpV@peKo(bX|M=115H&L zNQU0w)jx z0U$681_&yKNQUwETJcz*-tX5|=5@kD>GP4t(Z>5& zI|T-deqzE|D6;Rb4f(>diZz%m-Sq1%5<&wfAp{-~b%Ev#9K) z-$izRE%Rz_G$VLp_2essWi!^d9khI4dceQWJx_;2iNo%9#z`wc>U7nh>b9U+~`yBr%V zW1m|Fw#h>KIa%k(mcV};ilx5n&?#SkH1+xcY+5Kuw~A-ji@-M3N|dLz*uNzoaP>@o zJcQ@=98L)r>`v-fEDb2G=f8GM3cBn@)Gr|-N|AU@&wSzOjB*boZEU@<@$JtmVd}Ka zma<~NDDvI7!tpJy-biy$CTqwNOnFHwr9#x{coq|xt{QsP6av&`+;t8Z`1{tm1?(#a z9W9O3voabmh2-~ZjjpDJ8)H;gmk7>(gZM_zLLZ}GCnD$UmC@jGUgTZG%WL{<;uWuT zt}r)_Mfc9r-oaI$VYW`N|3m~gi`;&n#2>nF@Mf_RnB8{IbCMMHt>P;LWc+_g>1jWd z6ve#1F?;zvXj!!yMqn?GFL_EmS8FqBR#C^Mq(|)QwQ}+TD_Ipu!L#CJ3ebapyaoNG z_ZHjiV!^sGcN*@Xaf1wY_^~{hjd|xVg5q)@C_;U9*oN|VR)$)*-|>}88-Cq zh;_-`o<73b<`_@W(g0ufzbHC?f-dncidf8(mT-3wL-4h&JALv=7Jy8%hR7Zj3XDa7 z!h)@EW{I4X&5ERC8k8VxP#y0bZ!V*M;6_NMi;(_h z1gi5!JU%ItiXT*~@|0eI4$yWX58is%y;8G3)NrSk|5$8x2v-xH>ARC5EE7fS_0+Ez z>G=}eg71!0uh8uJV8qhau1xlxNXdLKd$soQO+KhLX1$Ugozz;UTcOS@g^bwQB2`iV^xxq zAi9e5032Bs;D)Z2m{f(mZ`FS_h>E@@&Y}5TNnmHU7CTAXhCE|`4ak{y_SlgAD2Z@5 z&f#YYkyw1NYP_Zwzd;NStAJn=tNdz}(mIHw>P$8z9c=uRGBhv({+1>Ow5)QMT}j02 z@yz(0SSIcztf|S6&D-1jluX>^N!!^#)+}~jv4`v3_&#?c9qsTc!?;UQXmBg_?eF9Z zmG;V|=duclL)@Z&-HYTI6Lx2s%Y&4)W38)(WgTbWN9t^yq6!%kv|D=~4!-LG-@N_w z!0l5E)W0)Qk%2M$;!B`f(NV)JYWmnOT;4A+y%X@y_6)89e}Ig1_|?t`GT8@|=M9yu z4!9MM?F_qHy5`yZo`f!0E@gAmp85a3Z+ka;`Zx|9ePZ{2;pC<|%>v7qjjUp7CuL2> z+}FM|UVcISO15$3TsU;bseJ_IBB-s&&NJn7Jr}HCD}xCf4GHDy2KM5V+M8Fj24WRo z8Bi`=-B&KD0wFa!h$sT1;;2cs|H-v}R|NrQSsntmIM)k?eyO7cIKZr2n;^G#@tPRu zkHji^!8iwhiBu^Rn{|fGo{v>W;aNxR9mF6z#gI=|t08xrR2{H=K*J0g+x{gLxe5-M z@Ja|`i#uQsq9ON6mSaYu#vgKI*)qL@7vLruN()cWX6K=kAPU~yG=DMAiyYam zwzU<24oKn3vl?frHQbHlySZA2EnFe)1SH?3$s5h(XK!kZ!dWk%lA7P%sa(DtOKy5e zx7zdi#y7rUAjg9|5_L&%@6#-SkZv-#6SmnJE{AY47-(Ee?155fH|Hi_kS5PuUdRTB+r zwojB{x8wNIRP38{k`wTc*-^yc)wV75X~?&Z0ydW(AHxs$u*28No6(QaHHD8hb$*r6 zUhSbF>to3Uby|Sp#^RjhJW}yIhEkc-?R2JpPbhx6r8|O0^mx5HM6Eslo?uV){DCQA zBgbm0o$m$j3(a*ZSOUhMDy_#{U3PYpDM<4oQC&FiolXgKK?~{s{8eWWvn-$JtII+- z)Q_XlPI<2fT{p3dQDddV&VuKCh!S5yW;g$>k1=a}#{;zMzmrAzb$vC9(+hxnM(f(;N#C(eT_l95+G`hD0e9{=A5 zP(ztTn^4(gVa731lXC?yKp_SRDuzgg_YDCF6)_Y95>#nzWgsy(FfuhXH!(0cFgYxB z=AVwhL68T+->D}bU=ap}d8FUOTW+u5?yiW%@4(5p5=CVjWSd^{=cyVg zW_0!@Bg&G9L!%`4jX#p$dR9+h{4DZoL*UNe3xh- zx}fpA2&Y(+IkprmMxG8KvB9LhRQ+3i*uTScnV)*6=bhQq0oe`7`_W8%=M(K4xw!N!kfl6p`?)rz>G0e?)ab=#NaRS#6B;a zNWqB8i893}vW;p!XUEQ{w;4y;H+DUlVt+n6QQBYHrw>au>HmMUh9mbdnoE({NN%>O zvXMMy8@3>!>0lR)ybgDhcyeqouqlY$`w{PB1`1%`(5MhUHpB4vg+dZOG1q7~f&~bC znzLF4Yrd3p2UDJ>8z+DJsSon7s?z~GYW516nRLVZwS>D*fFm6>N02#fxBV@)ihs8b zdKCYT2xx<7VnlpbwMnbfPT82 zA~}P`N59(RWB?N7)U9_>ev!z5uYXe4A=)ue7&Hc>R3VmuHkLCTZknNKMYRM?@gY8| znx$PW^BFK$*U#7>PJYzgO?(q_;8p%k?-(ZRe4RzJ6;K=&b_SHCeTspg>~V+8n3>2S z$>MBZ7b6ODaUi_H|DOfHAh6drHw?3%((u76Ll7fHdGLH}<{ALV3kUR*(0>>##6Pm( zg>CkEJmW5DH49F{Kuxp2{HwP@qMp&vZzEoyo>@A|>{p@YAPP6IN}Eps;6}dD3dBgZ zM6Yjqe@en6!VOxeoW;zlPNpLz)^OkMwDRl7NJ`ZcVQHyWm@dGK)rVU^c^LLo@J(0O z!A&28`mbqOg%%Px!ot<+(0}f!j4#C1Yo&VN1@IS_U94DMAQob~OJn4n6+G$PO!~~# zRc~Pux)G%fbK*=K0Fk_6b-DF4Mls2$Ue~c%n*knb+I)DSbuv>G%3@w0!<5INef|#U zeS~~J`3`|&$`!sQ{Lc_<&pQD?K#m!ndFy7*i-a)GA-tEvE%ggIC4aJM+{0Jq^KwVSI;HT-wyg-6$N721l0QpBgFJ;voD5;~m^ zhr@v47~QQ;DhF$cUw;`Qd1vFg-9KFbM_)D-Ht!8U+9Z6f@=Vve+Rp8YZjOVJ8bHviD5W%u=?T zs{Qx2s+Nr+IYiSUd#%0nGqY?1hM|xg5gYEZislU6spqkImwSMI%IJ7$pKK367<>9b_| zC;yZ!xjUyF>?ThM;d(brY-vYw3NuGymRTY7PmM}!X&jE>RjGH(@Xsnw+3H5ckSF`% zi@3E6#_aw$E*>PJ%CCT1AjzBNbP9mS*7C^+3&~*aZIt1*|LHicD+-U8<{Uhy1OvaT zU+lho)H3@R=MwY&w>T1NLjaq-zgq}cF(>l`3$&->r0R!(qVVlCNh6~$ZHZ4Z{V?nY zZ2V~RXLKK{eGQa#`mG>iy1jmDpPjP(!&7%t!@bt>Co%CsCqSjdba^S}-0c~5(MyV~ z1w}qa!yk#w8l2Or=%;|f!@oHvZ+*xlpHDK0bHhEe3rl!1Ct4|7TEg4A=K;LR)V`%y zZ$Ch%MKR2Kn<;*uK6m4h3)v>h?@{l1mNH{<3f3_Z-c1#s7Y(z>H5CyYu(j=oE?rOQPUz2(mRGPBn_?IOX=Zg3v?mYd8aK> zWI$3QOYBCp%Ewh`|GE58H^8=A<{ashQ^~j8TU`q97+KZCCrN0rgS#V8br`KXl>=G6mniOkgUs>PwT}cHrv7 zQlDj$aKEWJ(lu7-)zH*0;&C8P8*EZlB5x8--g~V1Y9rU;HIRHSHw1H__nFHKIXIFWOCDC=8gM56!2i4u;;Yo`@7BUNu{moUcTZfiiMXN3(Q!z|PuT^m0eQ{CNk`2AkVvR40Tq6J6{tc~12WG_3&qK=Uv|+_7 zb&Q_wzdNQn=%A-=j^cYQyK>sARJ8fXdkSu}A_~y6&w5MQdJw3a-c#Eg)R_@D&n0mG zIe(`L0OlLu9iOJoVHIXp88_@7Xb1EDImJz0|Ly}mtKhlw%;d~|S!gfn>J0}&>%_Po z34ft0N{wwjLO&dR8R}QjGXF3WCZvvpAnIoOUi3|(CVhmE7(Po5W9-}%fL6&s!c_qx zB;ucCPL4x{`W!OUiyg#vD6aocK>wmD$KO;fOdi?F)|1JW@3L5Q5vtsm;XCeiNL99I zB1EzBlk@Mx>ThSTr3FsS3sNiYc~{+mwB{Z}UwJ8WZ6|S_sw)h?;gFmc)Uo>ZWC4(l9;2%m)(BLpT1}ID7Mn8=FDJ!CL;X0vN%YCCZB%p z2!cH|iKXb!_eF7i<~pCViCn}KB==^5=xiBTf(j8yam4y@X zQ7G}g+F&DFhz!=ker`{TQTu&PpB|6hpEtA^Z3zL*KV2xLvKYykPu+-Bj;p$LfFtLozqaA?lf&OP4e`}&2|tc&gE{aPlKZ|VZYuyt2GiYB0Zwy zQY?{yA(|^~&lxXI8BU-s(0)Zcq>qL>gy_93Iy**tE;Ax|jkyVr-%sOUNF(_aY5M66 zbep+7A)cav#`PcTfe-yHf}5%dBHZtAO5F^PulyXdy=uJ%zX|nG?Emw<--6bZpbBoQe@|_(`br|@T_|{dX zK0kA%T~W9D&C0kw$j(o?w9C1DDnEj|r ziW!cYbk^;5|48qYHqO`i=ygMbevn}R-@PJmOs}_vjBLTK$Z|k|XYq0-I><+GOn%%4 ze_`?UU1Yc2N9k%^g*%g*N0;h`M40;Kr(P@p>SxxM2O_JExT`5!Yag&)ElP-9-Mh%= zPXe_?jX{z-bmZ*a1iOY)>jfx5kQva;lEJ^^3<6%ShtQPZA{&=I$9c0a*kZVA_DjpT zT%^(-7`xu}PddBw=jL(C+!(S!rtycY%1uWu2_kzdigY_W68b1B{|?2yxm3hCD+p8q zR4C*rR0Kq{l+2b0FX7=W-}s_-rXv90uOlXu<+nN7ZbQC8pZMb57{ULUVb zZ)liJ^qPI?_N$?Thl8!fDDJ}|_e_pJbLVdq04~1bMvvlGDv%8VM?Jr%vSCT&>J@4j zGtqg?PWqfi3)@uYRM*xs4E381sI!tX-LI^f>vR2zHb6_EVH{9pJ}|o&lnsJdz&uG0 sXcL)hKkA9g5`Q!2KSHtL!2kdN diff --git a/eidas-starterkit/src/test/resources/rsa-2048.p12 b/eidas-starterkit/src/test/resources/rsa-2048.p12 new file mode 100644 index 0000000000000000000000000000000000000000..c2e78e9cc58a250e50a78da1473c582d9d24c696 GIT binary patch literal 2524 zcma)8c{CJ^7N3=-F+yX>Iw5N_#*$qjlA*C=NtQ^2WX(=xWC_^^WnZ#|K?W)7$SB5V z`E1EPdPU+?{K&pr3I-2d+HTr2@L4g!L)1Q>w{CKYuxY8L@y2IdoB zz7PV;^Cx@{OMuq>7X>YX5TJQK;jEvP!36)0i{&H`luv+a{sh&r&c7T`1l9_x{Ci}< zN<)yx9EBIR1KuvsB<*D+kc0H4-6{?cNSqA>L}6K&PW*c#2nGdU1(;y=QCERZU6h;Rk z$~M76s;$P|b648rTDHe3VwmhcC6p6w?VYA3Ed$4JSQLVq7wm+v^<^BDEXx2Iuz~SL z-s?G_*cA5HrbE39LC|>8kYISBdrN8`c6h$N^zSxmZ##yk^PbC|qJ1$deP<=ZDI;Cc z9H1-zBqS|ljfW$6@>w>f;?$dI7oma^#pxdip-a8+*9l%Wu8*Bi>GJc;h) z(7SOWv8?v|j|C`pZG>B3PvgnNLxnfw%nVJse51fF$Jl#-!i^-l=u*!s6jG5n)y-;s zZ)>J2REJ05O8=mT^L})vO@wB2KKZk`!z;R_9)V--u6im<3CK|uJ@Tr#eC2Z-=t7tb zz43OV{?LSvL9OFa-;LUhEJZZ)QQC|YRREiP$@7Zybiu-}Y zOWTWJZr9u!-qIhxuUk2E>%g+~+bbkax%4WxCZqbBh19${vUQucxl2D{I)eSJqe+erG3>74{b#x zda|5s{Tj_a*Rs#X_Yu_ua>3nQ)fTD?$!&2y?|rgmC0EycL3$ZBw8M{?oz@ZkYq*|; zJDY;T8sF=wSQgi$n9yU+bNa`8z{n*k8g{5ztN(aU5|Iksk*hG z)3I09==V*Zzi(-QS(&`ZcRTboJDc-Hc}81f=jfkJm3Q@k)DXU-34trAoef{AapyV~ z8|WBhq~7g5D;d9DdE~RvUEI10FI5`f3ib~a4>oEk^Bk--FnQEaC|N}gp=#PUpr-K` z7ZkZ06MDj>h6izG?L?)Rd<9G!4yz)ze#f`Vq>PmgJ zUh-!G6RTd`GB+)YdFtG}EFS({wK3&Tl;5bm5$a#QH3z-bve%l>vi}?kPciZea2WC%%3XncgG1vF3gOM>6=rnMTlUSw215n8Rd z*D=|KhLbkSb)sKe4;Jj46u&)@j<$>7wIHotR9+nkF+P5~fcMN5+^At`t;`BHQ5ml% zDTK$%>R^R_#U%_W%OS`H@B#P&8~|v58~_VY04QV6{uXe`A|V`RuJ@f#vPxJvITa-p zS$R1nc`N~3`%A>klurN`{)BQtK)}zI@tXnuuc+R|kIWc(!>2ZyM^-%U3$=s-BQ^e? zsGint`cv%dfM$j{1EKI7FZ!4OM$Oo04p2l#u31P->?~s@C~RGkxcm!ebpTgW=m**} zr%i~#b_k=OoGyK)gt)_^c0R%3+QoKczJ_>$mB*`%){(cyfAH4qRygRg7*@mD-<>rv z`LVZU<9yvpaqfPm19P1}!u>kQQ}25%#i&y5GBaVI zdLut$UcgryvF!?Bl8gq_HEf6EP~tpKRK9c#{NvQt;TcR;JJ9g!Qgy#+D#D6VT5@8` z4B`q?JbS3Frf0A^82lsQt1f1{lzDMf;8d`c#qd4Ha?2*BSRW5}bRsCTY|Fzy!;LlS z1PW`}CAM1xK(yOljw&0uAl|I<$m3estTvb7bB06(OR`8lqZZPS zUxLe-W?SX5z;{r(_A{(5V1ou~Bheg$iJyf{N8^s8L)I>`vt3cBo+T5})>}nhbH%Gl zU!MVvI_iWzKKbhm;ah5aYQ37+l9W~idC=6{)MMt;*lSo>EaKP40|G(; z5R^kV>V~m4=<*a7)gX}0>3O~H!*EX@CqP$ni)Dm8 literal 0 HcmV?d00001 diff --git a/eidas-starterkit/src/test/resources/secp224r1.p12 b/eidas-starterkit/src/test/resources/secp224r1.p12 new file mode 100644 index 0000000000000000000000000000000000000000..de2d555275baca4100f221175e0da6e1a730891b GIT binary patch literal 1115 zcmXqLVhLwrWHxAGVPxafYV&CO&dbQoxS)yo6H62GJA)?XR|ZXti6~NxK`c#-en4R_ zAa-NphU((sVq{v-_|Bm5wLuzOJu9z4q=5y3%VVI;B62`q)Sct4?5FkhwigrE_vtoV z-^0noq%Oe3s9?au#sM*piIbJVK$eX&q0NIam6?T6i$&m?V#KB=U-<5v$&Py8Is3O6 zOJl?FuZR1)xsJN*Stiz2#=QGyn+VSyh3~SLgnl)$na#f~mnrXkLie%%F}=7IuXaZ- z-}0GTBSr99?;e%Z?YB*I<}b_t6_zV|^81X5wXd_B4ogcv*phg$H(o|>XU@YPo-=&R zPqZ&AsCgq2zq0J+wt&Q`TO{`XaaX;w(fw;#$Cs75mdgy?3>4wM;}kIzkrQGlW=Lg7 zW+-4V0zwmpA_hZbC8CBREJ7ifxv2_<<_1P4rpBfw#>S=w22D(jaC6w%7Bn#x0fq9I z7#V<6Izon#P}quzy{Xw?rhC$NUJ>8^&|Kz&VUiw9OdJe^!gd+&(J6NYjSEs&PTO)L zAoh4e6XS>Z$4)VST$J`%>qpI|YZAAPr0%QRHsSKu)#ooPbiHk|G~tl|2V4v(3w%YMqH z;>1+r*r-a5pWj!_Z9d88kh6)gqcI@Z;nSpm=e7dBSdJUJa_(ccFG`)*?D$r@vQ~T( z^OUG*i;~JWy^+~yxi_HUXwH?IloRzwUtFD5QlXT^k?>L6>95qv=8e;qgibuBu43le zQ`+g>SjF(B!Aduc>CRCd@o;U$WjlNJerIA#X^7E|Ta%r0+=XrRL^q$^jra3bs7pAB zED|Vt7@W5x)6ccsr~k_a)}`{i{%q3{LNCSIe7<2f?fLW4Snu!pbYM!DkKYzizi%$CkKgFP$@w>FI5@exLo*4kiEg z2}*7bk`l`H7BuiRFf`zWXE`QDRt6RYmFt!wi~`)T{1vl~aq&coN&T@<>T_=GJJ|hV i^HaT}48ZJcdBLvB^7PffpT+w99vf3 getCredentialType() { -+ return ECDHCredential.class; -+ } -+ -+ /** -+ * Constructor. -+ * -+ * @param entityCertificate -+ */ -+ public ECDHCredential(X509Certificate entityCertificate) { -+ super(entityCertificate); -+ } -+ -+ public ConcatKDFParamsType getConcatKDF() { -+ return concatKDF; -+ } -+ -+ public void setConcatKDF(ConcatKDFParamsType concatKDF) { -+ this.concatKDF = concatKDF; -+ } -+ -+ public PublicKey getSenderPubKey() { -+ return senderPubKey; -+ } -+ -+ public void setSenderPubKey(PublicKey senderPubKey) { -+ this.senderPubKey = senderPubKey; -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.security.x509; ++ ++import java.security.PublicKey; ++import java.security.cert.X509Certificate; ++ ++import javax.annotation.Nonnull; ++ ++import org.apache.xml.security.binding.xmlenc11.ConcatKDFParamsType; ++import org.opensaml.security.credential.Credential; ++ ++/** ++ * ++ */ ++public class ECDHCredential extends BasicX509Credential { ++ ++ private ConcatKDFParamsType concatKDF; ++ ++ private PublicKey senderPubKey; ++ ++ /** {@inheritDoc} */ ++ @Nonnull public Class getCredentialType() { ++ return ECDHCredential.class; ++ } ++ ++ /** ++ * Constructor. ++ * ++ * @param entityCertificate ++ */ ++ public ECDHCredential(X509Certificate entityCertificate) { ++ super(entityCertificate); ++ } ++ ++ public ConcatKDFParamsType getConcatKDF() { ++ return concatKDF; ++ } ++ ++ public void setConcatKDF(ConcatKDFParamsType concatKDF) { ++ this.concatKDF = concatKDF; ++ } ++ ++ public PublicKey getSenderPubKey() { ++ return senderPubKey; ++ } ++ ++ public void setSenderPubKey(PublicKey senderPubKey) { ++ this.senderPubKey = senderPubKey; ++ } ++} diff --git a/opensaml-security-impl/pom.xml b/opensaml-security-impl/pom.xml index 6854ea5..7de2603 100644 --- a/opensaml-security-impl/pom.xml @@ -573,207 +573,207 @@ index 0000000..7ed3523 --- /dev/null +++ b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/ConcatKDFParams.java @@ -0,0 +1,84 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption; -+ -+import javax.annotation.Nullable; -+import javax.xml.namespace.QName; -+ -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.xmlsec.encryption.support.EncryptionConstants; -+import org.opensaml.xmlsec.signature.DigestMethod; -+ -+/** -+ * -+ */ -+public interface ConcatKDFParams extends XMLObject { -+ -+ /** Element local name. */ -+ public static final String DEFAULT_ELEMENT_LOCAL_NAME = "ConcatKDFParams"; -+ -+ /** Default element name. */ -+ public static final QName DEFAULT_ELEMENT_NAME = -+ new QName(EncryptionConstants.XMLENC11_NS, DEFAULT_ELEMENT_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); -+ -+ /** Local name of the XSI type. */ -+ public static final String TYPE_LOCAL_NAME = "ConcatKDFParamsType"; -+ -+ /** QName of the XSI type. */ -+ public static final QName TYPE_NAME = -+ new QName(EncryptionConstants.XMLENC11_NS, TYPE_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); -+ -+ /** AlgorithmID attribute name. */ -+ public static final String ALGORITHMID_ATTRIBUTE_NAME = "AlgorithmID"; -+ -+ /** PartyUInfo attribute name. */ -+ public static final String PARTYUINFO_ATTRIBUTE_NAME = "PartyUInfo"; -+ -+ /** PartyVInfo attribute name. */ -+ public static final String PARTYVINFO_ATTRIBUTE_NAME = "PartyVInfo"; -+ -+ /** SuppPubInfo attribute name. */ -+ public static final String SUPPPUBINFO_ATTRIBUTE_NAME = "SuppPubInfo"; -+ -+ /** SuppPrivInfo attribute name. */ -+ public static final String SUPPPRIVINFO_ATTRIBUTE_NAME = "SuppPrivInfo"; -+ -+ @Nullable public byte[] getAlgorithmID(); -+ -+ public void setAlgorithmID(@Nullable byte[] algorithmID); -+ -+ @Nullable public byte[] getPartyUInfo(); -+ -+ public void setPartyUInfo(@Nullable byte[] partyUInfo); -+ -+ @Nullable public byte[] getPartyVInfo(); -+ -+ public void setPartyVInfo(@Nullable byte[] partyVInfo); -+ -+ @Nullable public byte[] getSuppPubInfo(); -+ -+ public void setSuppPubInfo(@Nullable byte[] suppPubInfo); -+ -+ @Nullable public byte[] getSuppPrivInfo(); -+ -+ public void setSuppPrivInfo(@Nullable byte[] suppPrivInfo); -+ -+ @Nullable public DigestMethod getDigestMethod(); -+ -+ public void setDigestMethod(DigestMethod digestMethod); -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption; ++ ++import javax.annotation.Nullable; ++import javax.xml.namespace.QName; ++ ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.xmlsec.encryption.support.EncryptionConstants; ++import org.opensaml.xmlsec.signature.DigestMethod; ++ ++/** ++ * ++ */ ++public interface ConcatKDFParams extends XMLObject { ++ ++ /** Element local name. */ ++ public static final String DEFAULT_ELEMENT_LOCAL_NAME = "ConcatKDFParams"; ++ ++ /** Default element name. */ ++ public static final QName DEFAULT_ELEMENT_NAME = ++ new QName(EncryptionConstants.XMLENC11_NS, DEFAULT_ELEMENT_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); ++ ++ /** Local name of the XSI type. */ ++ public static final String TYPE_LOCAL_NAME = "ConcatKDFParamsType"; ++ ++ /** QName of the XSI type. */ ++ public static final QName TYPE_NAME = ++ new QName(EncryptionConstants.XMLENC11_NS, TYPE_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); ++ ++ /** AlgorithmID attribute name. */ ++ public static final String ALGORITHMID_ATTRIBUTE_NAME = "AlgorithmID"; ++ ++ /** PartyUInfo attribute name. */ ++ public static final String PARTYUINFO_ATTRIBUTE_NAME = "PartyUInfo"; ++ ++ /** PartyVInfo attribute name. */ ++ public static final String PARTYVINFO_ATTRIBUTE_NAME = "PartyVInfo"; ++ ++ /** SuppPubInfo attribute name. */ ++ public static final String SUPPPUBINFO_ATTRIBUTE_NAME = "SuppPubInfo"; ++ ++ /** SuppPrivInfo attribute name. */ ++ public static final String SUPPPRIVINFO_ATTRIBUTE_NAME = "SuppPrivInfo"; ++ ++ @Nullable public byte[] getAlgorithmID(); ++ ++ public void setAlgorithmID(@Nullable byte[] algorithmID); ++ ++ @Nullable public byte[] getPartyUInfo(); ++ ++ public void setPartyUInfo(@Nullable byte[] partyUInfo); ++ ++ @Nullable public byte[] getPartyVInfo(); ++ ++ public void setPartyVInfo(@Nullable byte[] partyVInfo); ++ ++ @Nullable public byte[] getSuppPubInfo(); ++ ++ public void setSuppPubInfo(@Nullable byte[] suppPubInfo); ++ ++ @Nullable public byte[] getSuppPrivInfo(); ++ ++ public void setSuppPrivInfo(@Nullable byte[] suppPrivInfo); ++ ++ @Nullable public DigestMethod getDigestMethod(); ++ ++ public void setDigestMethod(DigestMethod digestMethod); ++} diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/KeyDerivationMethod.java b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/KeyDerivationMethod.java new file mode 100644 index 0000000..6ba3d11 --- /dev/null +++ b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/KeyDerivationMethod.java @@ -0,0 +1,62 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption; -+ -+import javax.annotation.Nullable; -+import javax.xml.namespace.QName; -+ -+import org.opensaml.core.xml.ElementExtensibleXMLObject; -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.xmlsec.encryption.support.EncryptionConstants; -+ -+/** -+ * -+ */ -+public interface KeyDerivationMethod extends XMLObject, ElementExtensibleXMLObject { -+ -+ /** Element local name. */ -+ public static final String DEFAULT_ELEMENT_LOCAL_NAME = "KeyDerivationMethod"; -+ -+ /** Default element name. */ -+ public static final QName DEFAULT_ELEMENT_NAME = -+ new QName(EncryptionConstants.XMLENC11_NS, DEFAULT_ELEMENT_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); -+ -+ /** Local name of the XSI type. */ -+ public static final String TYPE_LOCAL_NAME = "KeyDerivationMethodType"; -+ -+ /** QName of the XSI type. */ -+ public static final QName TYPE_NAME = -+ new QName(EncryptionConstants.XMLENC11_NS, TYPE_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); -+ -+ /** Algorithm attribute name. */ -+ public static final String ALGORITHM_ATTRIBUTE_NAME = "Algorithm"; -+ -+ /** -+ * Gets the algorithm URI attribute value for this agreement method. -+ * -+ * @return the algorithm URI attribute value -+ */ -+ @Nullable public String getAlgorithm(); -+ -+ /** -+ * Sets the algorithm URI attribute value for this agreement method. -+ * -+ * @param newAlgorithm the new algorithm URI attribute value -+ */ -+ public void setAlgorithm(@Nullable final String newAlgorithm); -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption; ++ ++import javax.annotation.Nullable; ++import javax.xml.namespace.QName; ++ ++import org.opensaml.core.xml.ElementExtensibleXMLObject; ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.xmlsec.encryption.support.EncryptionConstants; ++ ++/** ++ * ++ */ ++public interface KeyDerivationMethod extends XMLObject, ElementExtensibleXMLObject { ++ ++ /** Element local name. */ ++ public static final String DEFAULT_ELEMENT_LOCAL_NAME = "KeyDerivationMethod"; ++ ++ /** Default element name. */ ++ public static final QName DEFAULT_ELEMENT_NAME = ++ new QName(EncryptionConstants.XMLENC11_NS, DEFAULT_ELEMENT_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); ++ ++ /** Local name of the XSI type. */ ++ public static final String TYPE_LOCAL_NAME = "KeyDerivationMethodType"; ++ ++ /** QName of the XSI type. */ ++ public static final QName TYPE_NAME = ++ new QName(EncryptionConstants.XMLENC11_NS, TYPE_LOCAL_NAME, EncryptionConstants.XMLENC11_PREFIX); ++ ++ /** Algorithm attribute name. */ ++ public static final String ALGORITHM_ATTRIBUTE_NAME = "Algorithm"; ++ ++ /** ++ * Gets the algorithm URI attribute value for this agreement method. ++ * ++ * @return the algorithm URI attribute value ++ */ ++ @Nullable public String getAlgorithm(); ++ ++ /** ++ * Sets the algorithm URI attribute value for this agreement method. ++ * ++ * @param newAlgorithm the new algorithm URI attribute value ++ */ ++ public void setAlgorithm(@Nullable final String newAlgorithm); ++} diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/support/ECDHParameters.java b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/support/ECDHParameters.java new file mode 100644 index 0000000..226a090 --- /dev/null +++ b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/support/ECDHParameters.java @@ -0,0 +1,43 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.support; -+ -+/** -+ * -+ */ -+public class ECDHParameters { -+ -+ /** -+ * key wrapping algorithm. -+ */ -+ private String keyWrapMethod; -+ -+ /** -+ * @return Returns the keyWrapMethod. -+ */ -+ public String getKeyWrapMethod() { -+ return keyWrapMethod; -+ } -+ -+ /** -+ * @param keyWrapMethod The keyWrapMethod to set. -+ */ -+ public void setKeyWrapMethod(String keyWrapMethod) { -+ this.keyWrapMethod = keyWrapMethod; -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.support; ++ ++/** ++ * ++ */ ++public class ECDHParameters { ++ ++ /** ++ * key wrapping algorithm. ++ */ ++ private String keyWrapMethod; ++ ++ /** ++ * @return Returns the keyWrapMethod. ++ */ ++ public String getKeyWrapMethod() { ++ return keyWrapMethod; ++ } ++ ++ /** ++ * @param keyWrapMethod The keyWrapMethod to set. ++ */ ++ public void setKeyWrapMethod(String keyWrapMethod) { ++ this.keyWrapMethod = keyWrapMethod; ++ } ++} diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/support/Encrypter.java b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/support/Encrypter.java index cb955b8..d23bd04 100644 --- a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/encryption/support/Encrypter.java @@ -1163,669 +1163,669 @@ index 0000000..b8d71ac --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsBuilder.java @@ -0,0 +1,41 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import org.opensaml.core.xml.AbstractXMLObjectBuilder; -+import org.opensaml.xmlsec.encryption.ConcatKDFParams; -+import org.opensaml.xmlsec.encryption.XMLEncryptionBuilder; -+import org.opensaml.xmlsec.encryption.support.EncryptionConstants; -+ -+/** -+ * -+ */ -+public class ConcatKDFParamsBuilder extends AbstractXMLObjectBuilder -+ implements XMLEncryptionBuilder { -+ -+ /** {@inheritDoc} */ -+ public ConcatKDFParams buildObject() { -+ return buildObject(EncryptionConstants.XMLENC11_NS, ConcatKDFParams.DEFAULT_ELEMENT_LOCAL_NAME, -+ EncryptionConstants.XMLENC11_PREFIX); -+ } -+ -+ /** {@inheritDoc} */ -+ public ConcatKDFParams buildObject(String namespaceURI, String localName, String namespacePrefix) { -+ return new ConcatKDFParamsImpl(namespaceURI, localName, namespacePrefix); -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import org.opensaml.core.xml.AbstractXMLObjectBuilder; ++import org.opensaml.xmlsec.encryption.ConcatKDFParams; ++import org.opensaml.xmlsec.encryption.XMLEncryptionBuilder; ++import org.opensaml.xmlsec.encryption.support.EncryptionConstants; ++ ++/** ++ * ++ */ ++public class ConcatKDFParamsBuilder extends AbstractXMLObjectBuilder ++ implements XMLEncryptionBuilder { ++ ++ /** {@inheritDoc} */ ++ public ConcatKDFParams buildObject() { ++ return buildObject(EncryptionConstants.XMLENC11_NS, ConcatKDFParams.DEFAULT_ELEMENT_LOCAL_NAME, ++ EncryptionConstants.XMLENC11_PREFIX); ++ } ++ ++ /** {@inheritDoc} */ ++ public ConcatKDFParams buildObject(String namespaceURI, String localName, String namespacePrefix) { ++ return new ConcatKDFParamsImpl(namespaceURI, localName, namespacePrefix); ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsImpl.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsImpl.java new file mode 100644 index 0000000..f38f337 --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsImpl.java @@ -0,0 +1,114 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.List; -+ -+import org.opensaml.core.xml.AbstractXMLObject; -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.xmlsec.encryption.ConcatKDFParams; -+import org.opensaml.xmlsec.signature.DigestMethod; -+ -+/** -+ * -+ */ -+public class ConcatKDFParamsImpl extends AbstractXMLObject implements ConcatKDFParams { -+ -+ private byte[] algorithmID; -+ -+ private byte[] partyUInfo; -+ -+ private byte[] partyVInfo; -+ -+ private byte[] suppPubInfo; -+ -+ private byte[] suppPrivInfo; -+ -+ private DigestMethod digestMethod; -+ -+ /** -+ * Constructor. -+ * -+ * @param namespaceURI -+ * @param elementLocalName -+ * @param namespacePrefix -+ */ -+ protected ConcatKDFParamsImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { -+ super(namespaceURI, elementLocalName, namespacePrefix); -+ } -+ -+ /** {@inheritDoc} */ -+ public List getOrderedChildren() { -+ if (digestMethod == null) { -+ return null; -+ } -+ List result = new ArrayList<>(); -+ result.add(digestMethod); -+ return Collections.unmodifiableList(result); -+ } -+ -+ public byte[] getAlgorithmID() { -+ return algorithmID; -+ } -+ -+ public void setAlgorithmID(byte[] algorithmID) { -+ this.algorithmID = algorithmID; -+ } -+ -+ public byte[] getPartyUInfo() { -+ return partyUInfo; -+ } -+ -+ public void setPartyUInfo(byte[] partyUInfo) { -+ this.partyUInfo = partyUInfo; -+ } -+ -+ public byte[] getPartyVInfo() { -+ return partyVInfo; -+ } -+ -+ public void setPartyVInfo(byte[] partyVInfo) { -+ this.partyVInfo = partyVInfo; -+ } -+ -+ public byte[] getSuppPubInfo() { -+ return suppPubInfo; -+ } -+ -+ public void setSuppPubInfo(byte[] suppPubInfo) { -+ this.suppPubInfo = suppPubInfo; -+ } -+ -+ public byte[] getSuppPrivInfo() { -+ return suppPrivInfo; -+ } -+ -+ public void setSuppPrivInfo(byte[] suppPrivInfo) { -+ this.suppPrivInfo = suppPrivInfo; -+ } -+ -+ public DigestMethod getDigestMethod() { -+ return digestMethod; -+ } -+ -+ public void setDigestMethod(DigestMethod digestMethod) { -+ this.digestMethod = digestMethod; -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.List; ++ ++import org.opensaml.core.xml.AbstractXMLObject; ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.xmlsec.encryption.ConcatKDFParams; ++import org.opensaml.xmlsec.signature.DigestMethod; ++ ++/** ++ * ++ */ ++public class ConcatKDFParamsImpl extends AbstractXMLObject implements ConcatKDFParams { ++ ++ private byte[] algorithmID; ++ ++ private byte[] partyUInfo; ++ ++ private byte[] partyVInfo; ++ ++ private byte[] suppPubInfo; ++ ++ private byte[] suppPrivInfo; ++ ++ private DigestMethod digestMethod; ++ ++ /** ++ * Constructor. ++ * ++ * @param namespaceURI ++ * @param elementLocalName ++ * @param namespacePrefix ++ */ ++ protected ConcatKDFParamsImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { ++ super(namespaceURI, elementLocalName, namespacePrefix); ++ } ++ ++ /** {@inheritDoc} */ ++ public List getOrderedChildren() { ++ if (digestMethod == null) { ++ return null; ++ } ++ List result = new ArrayList<>(); ++ result.add(digestMethod); ++ return Collections.unmodifiableList(result); ++ } ++ ++ public byte[] getAlgorithmID() { ++ return algorithmID; ++ } ++ ++ public void setAlgorithmID(byte[] algorithmID) { ++ this.algorithmID = algorithmID; ++ } ++ ++ public byte[] getPartyUInfo() { ++ return partyUInfo; ++ } ++ ++ public void setPartyUInfo(byte[] partyUInfo) { ++ this.partyUInfo = partyUInfo; ++ } ++ ++ public byte[] getPartyVInfo() { ++ return partyVInfo; ++ } ++ ++ public void setPartyVInfo(byte[] partyVInfo) { ++ this.partyVInfo = partyVInfo; ++ } ++ ++ public byte[] getSuppPubInfo() { ++ return suppPubInfo; ++ } ++ ++ public void setSuppPubInfo(byte[] suppPubInfo) { ++ this.suppPubInfo = suppPubInfo; ++ } ++ ++ public byte[] getSuppPrivInfo() { ++ return suppPrivInfo; ++ } ++ ++ public void setSuppPrivInfo(byte[] suppPrivInfo) { ++ this.suppPrivInfo = suppPrivInfo; ++ } ++ ++ public DigestMethod getDigestMethod() { ++ return digestMethod; ++ } ++ ++ public void setDigestMethod(DigestMethod digestMethod) { ++ this.digestMethod = digestMethod; ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsMarshaller.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsMarshaller.java new file mode 100644 index 0000000..39b8f81 --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsMarshaller.java @@ -0,0 +1,56 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import org.bouncycastle.util.encoders.Hex; -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.core.xml.io.MarshallingException; -+import org.opensaml.xmlsec.encryption.ConcatKDFParams; -+import org.w3c.dom.Element; -+ -+/** -+ * -+ */ -+public class ConcatKDFParamsMarshaller extends AbstractXMLEncryptionMarshaller { -+ /** {@inheritDoc} */ -+ protected void marshallAttributes(final XMLObject xmlObject, final Element domElement) throws MarshallingException { -+ final ConcatKDFParams kdfParams = (ConcatKDFParams) xmlObject; -+ -+ if (kdfParams.getAlgorithmID() != null) { -+ domElement.setAttributeNS(null, ConcatKDFParams.ALGORITHMID_ATTRIBUTE_NAME, -+ Hex.toHexString(kdfParams.getAlgorithmID())); -+ } -+ if (kdfParams.getPartyUInfo() != null) { -+ domElement.setAttributeNS(null, ConcatKDFParams.PARTYUINFO_ATTRIBUTE_NAME, -+ Hex.toHexString(kdfParams.getPartyUInfo())); -+ } -+ if (kdfParams.getPartyVInfo() != null) { -+ domElement.setAttributeNS(null, ConcatKDFParams.PARTYVINFO_ATTRIBUTE_NAME, -+ Hex.toHexString(kdfParams.getPartyVInfo())); -+ } -+ if (kdfParams.getSuppPrivInfo() != null) { -+ domElement.setAttributeNS(null, ConcatKDFParams.SUPPPRIVINFO_ATTRIBUTE_NAME, -+ Hex.toHexString(kdfParams.getSuppPrivInfo())); -+ } -+ if (kdfParams.getSuppPubInfo() != null) { -+ domElement.setAttributeNS(null, ConcatKDFParams.SUPPPUBINFO_ATTRIBUTE_NAME, -+ Hex.toHexString(kdfParams.getSuppPubInfo())); -+ } -+ } -+ -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import org.bouncycastle.util.encoders.Hex; ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.core.xml.io.MarshallingException; ++import org.opensaml.xmlsec.encryption.ConcatKDFParams; ++import org.w3c.dom.Element; ++ ++/** ++ * ++ */ ++public class ConcatKDFParamsMarshaller extends AbstractXMLEncryptionMarshaller { ++ /** {@inheritDoc} */ ++ protected void marshallAttributes(final XMLObject xmlObject, final Element domElement) throws MarshallingException { ++ final ConcatKDFParams kdfParams = (ConcatKDFParams) xmlObject; ++ ++ if (kdfParams.getAlgorithmID() != null) { ++ domElement.setAttributeNS(null, ConcatKDFParams.ALGORITHMID_ATTRIBUTE_NAME, ++ Hex.toHexString(kdfParams.getAlgorithmID())); ++ } ++ if (kdfParams.getPartyUInfo() != null) { ++ domElement.setAttributeNS(null, ConcatKDFParams.PARTYUINFO_ATTRIBUTE_NAME, ++ Hex.toHexString(kdfParams.getPartyUInfo())); ++ } ++ if (kdfParams.getPartyVInfo() != null) { ++ domElement.setAttributeNS(null, ConcatKDFParams.PARTYVINFO_ATTRIBUTE_NAME, ++ Hex.toHexString(kdfParams.getPartyVInfo())); ++ } ++ if (kdfParams.getSuppPrivInfo() != null) { ++ domElement.setAttributeNS(null, ConcatKDFParams.SUPPPRIVINFO_ATTRIBUTE_NAME, ++ Hex.toHexString(kdfParams.getSuppPrivInfo())); ++ } ++ if (kdfParams.getSuppPubInfo() != null) { ++ domElement.setAttributeNS(null, ConcatKDFParams.SUPPPUBINFO_ATTRIBUTE_NAME, ++ Hex.toHexString(kdfParams.getSuppPubInfo())); ++ } ++ } ++ ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsUnmarshaller.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsUnmarshaller.java new file mode 100644 index 0000000..698042b --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/ConcatKDFParamsUnmarshaller.java @@ -0,0 +1,67 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import org.apache.commons.codec.DecoderException; -+import org.apache.commons.codec.binary.Hex; -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.core.xml.io.UnmarshallingException; -+import org.opensaml.xmlsec.encryption.AgreementMethod; -+import org.opensaml.xmlsec.encryption.ConcatKDFParams; -+import org.opensaml.xmlsec.encryption.KANonce; -+import org.opensaml.xmlsec.encryption.OriginatorKeyInfo; -+import org.opensaml.xmlsec.encryption.RecipientKeyInfo; -+import org.opensaml.xmlsec.signature.DigestMethod; -+import org.w3c.dom.Attr; -+ -+/** -+ * -+ */ -+public class ConcatKDFParamsUnmarshaller extends AbstractXMLEncryptionUnmarshaller { -+ -+ /** {@inheritDoc} */ -+ protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { -+ -+ final ConcatKDFParams concat = (ConcatKDFParams) xmlObject; -+ try { -+ if (attribute.getLocalName().equals(ConcatKDFParams.ALGORITHMID_ATTRIBUTE_NAME)) { -+ concat.setAlgorithmID(Hex.decodeHex(attribute.getValue().toCharArray())); -+ } else if (attribute.getLocalName().equals(ConcatKDFParams.PARTYUINFO_ATTRIBUTE_NAME)) { -+ concat.setPartyUInfo(Hex.decodeHex(attribute.getValue().toCharArray())); -+ } else if (attribute.getLocalName().equals(ConcatKDFParams.PARTYVINFO_ATTRIBUTE_NAME)) { -+ concat.setPartyVInfo(Hex.decodeHex(attribute.getValue().toCharArray())); -+ } else if (attribute.getLocalName().equals(ConcatKDFParams.SUPPPRIVINFO_ATTRIBUTE_NAME)) { -+ concat.setSuppPrivInfo(Hex.decodeHex(attribute.getValue().toCharArray())); -+ } else if (attribute.getLocalName().equals(ConcatKDFParams.SUPPPUBINFO_ATTRIBUTE_NAME)) { -+ concat.setSuppPubInfo(Hex.decodeHex(attribute.getValue().toCharArray())); -+ } -+ } catch (DecoderException e) { -+ throw new UnmarshallingException(e); -+ } -+ } -+ -+ /** {@inheritDoc} */ -+ protected void processChildElement(final XMLObject parentXMLObject, final XMLObject childXMLObject) -+ throws UnmarshallingException { -+ final ConcatKDFParams concat = (ConcatKDFParams) parentXMLObject; -+ -+ if (childXMLObject instanceof DigestMethod) { -+ concat.setDigestMethod((DigestMethod) childXMLObject); -+ } -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import org.apache.commons.codec.DecoderException; ++import org.apache.commons.codec.binary.Hex; ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.core.xml.io.UnmarshallingException; ++import org.opensaml.xmlsec.encryption.AgreementMethod; ++import org.opensaml.xmlsec.encryption.ConcatKDFParams; ++import org.opensaml.xmlsec.encryption.KANonce; ++import org.opensaml.xmlsec.encryption.OriginatorKeyInfo; ++import org.opensaml.xmlsec.encryption.RecipientKeyInfo; ++import org.opensaml.xmlsec.signature.DigestMethod; ++import org.w3c.dom.Attr; ++ ++/** ++ * ++ */ ++public class ConcatKDFParamsUnmarshaller extends AbstractXMLEncryptionUnmarshaller { ++ ++ /** {@inheritDoc} */ ++ protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { ++ ++ final ConcatKDFParams concat = (ConcatKDFParams) xmlObject; ++ try { ++ if (attribute.getLocalName().equals(ConcatKDFParams.ALGORITHMID_ATTRIBUTE_NAME)) { ++ concat.setAlgorithmID(Hex.decodeHex(attribute.getValue().toCharArray())); ++ } else if (attribute.getLocalName().equals(ConcatKDFParams.PARTYUINFO_ATTRIBUTE_NAME)) { ++ concat.setPartyUInfo(Hex.decodeHex(attribute.getValue().toCharArray())); ++ } else if (attribute.getLocalName().equals(ConcatKDFParams.PARTYVINFO_ATTRIBUTE_NAME)) { ++ concat.setPartyVInfo(Hex.decodeHex(attribute.getValue().toCharArray())); ++ } else if (attribute.getLocalName().equals(ConcatKDFParams.SUPPPRIVINFO_ATTRIBUTE_NAME)) { ++ concat.setSuppPrivInfo(Hex.decodeHex(attribute.getValue().toCharArray())); ++ } else if (attribute.getLocalName().equals(ConcatKDFParams.SUPPPUBINFO_ATTRIBUTE_NAME)) { ++ concat.setSuppPubInfo(Hex.decodeHex(attribute.getValue().toCharArray())); ++ } ++ } catch (DecoderException e) { ++ throw new UnmarshallingException(e); ++ } ++ } ++ ++ /** {@inheritDoc} */ ++ protected void processChildElement(final XMLObject parentXMLObject, final XMLObject childXMLObject) ++ throws UnmarshallingException { ++ final ConcatKDFParams concat = (ConcatKDFParams) parentXMLObject; ++ ++ if (childXMLObject instanceof DigestMethod) { ++ concat.setDigestMethod((DigestMethod) childXMLObject); ++ } ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodBuilder.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodBuilder.java new file mode 100644 index 0000000..1b0bc19 --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodBuilder.java @@ -0,0 +1,41 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import org.opensaml.core.xml.AbstractXMLObjectBuilder; -+import org.opensaml.xmlsec.encryption.KeyDerivationMethod; -+import org.opensaml.xmlsec.encryption.XMLEncryptionBuilder; -+import org.opensaml.xmlsec.encryption.support.EncryptionConstants; -+ -+/** -+ * -+ */ -+public class KeyDerivationMethodBuilder extends AbstractXMLObjectBuilder -+ implements XMLEncryptionBuilder { -+ -+ /** {@inheritDoc} */ -+ public KeyDerivationMethod buildObject() { -+ return buildObject(EncryptionConstants.XMLENC11_NS, KeyDerivationMethod.DEFAULT_ELEMENT_LOCAL_NAME, -+ EncryptionConstants.XMLENC11_PREFIX); -+ } -+ -+ /** {@inheritDoc} */ -+ public KeyDerivationMethod buildObject(String namespaceURI, String localName, String namespacePrefix) { -+ return new KeyDerivationMethodImpl(namespaceURI, localName, namespacePrefix); -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import org.opensaml.core.xml.AbstractXMLObjectBuilder; ++import org.opensaml.xmlsec.encryption.KeyDerivationMethod; ++import org.opensaml.xmlsec.encryption.XMLEncryptionBuilder; ++import org.opensaml.xmlsec.encryption.support.EncryptionConstants; ++ ++/** ++ * ++ */ ++public class KeyDerivationMethodBuilder extends AbstractXMLObjectBuilder ++ implements XMLEncryptionBuilder { ++ ++ /** {@inheritDoc} */ ++ public KeyDerivationMethod buildObject() { ++ return buildObject(EncryptionConstants.XMLENC11_NS, KeyDerivationMethod.DEFAULT_ELEMENT_LOCAL_NAME, ++ EncryptionConstants.XMLENC11_PREFIX); ++ } ++ ++ /** {@inheritDoc} */ ++ public KeyDerivationMethod buildObject(String namespaceURI, String localName, String namespacePrefix) { ++ return new KeyDerivationMethodImpl(namespaceURI, localName, namespacePrefix); ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodImpl.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodImpl.java new file mode 100644 index 0000000..d3bef7d --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodImpl.java @@ -0,0 +1,83 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.List; -+ -+import javax.xml.namespace.QName; -+ -+import org.opensaml.core.xml.AbstractXMLObject; -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList; -+import org.opensaml.xmlsec.encryption.KeyDerivationMethod; -+ -+/** -+ * -+ */ -+public class KeyDerivationMethodImpl extends AbstractXMLObject implements KeyDerivationMethod { -+ -+ /** Algorithm attribute value. */ -+ private String algorithm; -+ -+ /** List of wildcard <any> XMLObject children. */ -+ private IndexedXMLObjectChildrenList xmlChildren; -+ -+ /** -+ * Constructor. -+ * -+ * @param namespaceURI -+ * @param elementLocalName -+ * @param namespacePrefix -+ */ -+ protected KeyDerivationMethodImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { -+ super(namespaceURI, elementLocalName, namespacePrefix); -+ xmlChildren = new IndexedXMLObjectChildrenList(this); -+ } -+ -+ /** {@inheritDoc} */ -+ public List getOrderedChildren() { -+ final ArrayList children = new ArrayList<>(); -+ children.addAll(xmlChildren); -+ if (children.size() == 0) { -+ return null; -+ } -+ return Collections.unmodifiableList(children); -+ } -+ -+ /** {@inheritDoc} */ -+ public List getUnknownXMLObjects() { -+ return (List) this.xmlChildren; -+ } -+ -+ /** {@inheritDoc} */ -+ public List getUnknownXMLObjects(final QName typeOrName) { -+ return (List) this.xmlChildren.subList(typeOrName); -+ } -+ -+ /** {@inheritDoc} */ -+ public String getAlgorithm() { -+ return this.algorithm; -+ } -+ -+ /** {@inheritDoc} */ -+ public void setAlgorithm(final String newAlgorithm) { -+ this.algorithm = prepareForAssignment(this.algorithm, newAlgorithm); -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.List; ++ ++import javax.xml.namespace.QName; ++ ++import org.opensaml.core.xml.AbstractXMLObject; ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.core.xml.util.IndexedXMLObjectChildrenList; ++import org.opensaml.xmlsec.encryption.KeyDerivationMethod; ++ ++/** ++ * ++ */ ++public class KeyDerivationMethodImpl extends AbstractXMLObject implements KeyDerivationMethod { ++ ++ /** Algorithm attribute value. */ ++ private String algorithm; ++ ++ /** List of wildcard <any> XMLObject children. */ ++ private IndexedXMLObjectChildrenList xmlChildren; ++ ++ /** ++ * Constructor. ++ * ++ * @param namespaceURI ++ * @param elementLocalName ++ * @param namespacePrefix ++ */ ++ protected KeyDerivationMethodImpl(String namespaceURI, String elementLocalName, String namespacePrefix) { ++ super(namespaceURI, elementLocalName, namespacePrefix); ++ xmlChildren = new IndexedXMLObjectChildrenList(this); ++ } ++ ++ /** {@inheritDoc} */ ++ public List getOrderedChildren() { ++ final ArrayList children = new ArrayList<>(); ++ children.addAll(xmlChildren); ++ if (children.size() == 0) { ++ return null; ++ } ++ return Collections.unmodifiableList(children); ++ } ++ ++ /** {@inheritDoc} */ ++ public List getUnknownXMLObjects() { ++ return (List) this.xmlChildren; ++ } ++ ++ /** {@inheritDoc} */ ++ public List getUnknownXMLObjects(final QName typeOrName) { ++ return (List) this.xmlChildren.subList(typeOrName); ++ } ++ ++ /** {@inheritDoc} */ ++ public String getAlgorithm() { ++ return this.algorithm; ++ } ++ ++ /** {@inheritDoc} */ ++ public void setAlgorithm(final String newAlgorithm) { ++ this.algorithm = prepareForAssignment(this.algorithm, newAlgorithm); ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodMarshaller.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodMarshaller.java new file mode 100644 index 0000000..0bfa33d --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodMarshaller.java @@ -0,0 +1,38 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.core.xml.io.MarshallingException; -+import org.opensaml.xmlsec.encryption.KeyDerivationMethod; -+import org.w3c.dom.Element; -+ -+/** -+ * -+ */ -+public class KeyDerivationMethodMarshaller extends AbstractXMLEncryptionMarshaller { -+ -+ /** {@inheritDoc} */ -+ protected void marshallAttributes(final XMLObject xmlObject, final Element domElement) throws MarshallingException { -+ final KeyDerivationMethod kdm = (KeyDerivationMethod) xmlObject; -+ -+ if (kdm.getAlgorithm() != null) { -+ domElement.setAttributeNS(null, KeyDerivationMethod.ALGORITHM_ATTRIBUTE_NAME, kdm.getAlgorithm()); -+ } -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.core.xml.io.MarshallingException; ++import org.opensaml.xmlsec.encryption.KeyDerivationMethod; ++import org.w3c.dom.Element; ++ ++/** ++ * ++ */ ++public class KeyDerivationMethodMarshaller extends AbstractXMLEncryptionMarshaller { ++ ++ /** {@inheritDoc} */ ++ protected void marshallAttributes(final XMLObject xmlObject, final Element domElement) throws MarshallingException { ++ final KeyDerivationMethod kdm = (KeyDerivationMethod) xmlObject; ++ ++ if (kdm.getAlgorithm() != null) { ++ domElement.setAttributeNS(null, KeyDerivationMethod.ALGORITHM_ATTRIBUTE_NAME, kdm.getAlgorithm()); ++ } ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodUnmarshaller.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodUnmarshaller.java new file mode 100644 index 0000000..8420bc2 --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/encryption/impl/KeyDerivationMethodUnmarshaller.java @@ -0,0 +1,50 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.encryption.impl; -+ -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.core.xml.io.UnmarshallingException; -+import org.opensaml.xmlsec.encryption.AgreementMethod; -+import org.opensaml.xmlsec.encryption.KANonce; -+import org.opensaml.xmlsec.encryption.KeyDerivationMethod; -+import org.opensaml.xmlsec.encryption.OriginatorKeyInfo; -+import org.opensaml.xmlsec.encryption.RecipientKeyInfo; -+import org.w3c.dom.Attr; -+ -+/** -+ * -+ */ -+public class KeyDerivationMethodUnmarshaller extends AbstractXMLEncryptionUnmarshaller { -+ -+ /** {@inheritDoc} */ -+ protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { -+ -+ final KeyDerivationMethod kdm = (KeyDerivationMethod) xmlObject; -+ if (attribute.getLocalName().equals(KeyDerivationMethod.ALGORITHM_ATTRIBUTE_NAME)) { -+ kdm.setAlgorithm(attribute.getValue()); -+ attribute.getOwnerElement().setIdAttributeNode(attribute, true); -+ } -+ } -+ -+ /** {@inheritDoc} */ -+ protected void processChildElement(final XMLObject parentXMLObject, final XMLObject childXMLObject) -+ throws UnmarshallingException { -+ final KeyDerivationMethod am = (KeyDerivationMethod) parentXMLObject; -+ am.getUnknownXMLObjects().add(childXMLObject); -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.encryption.impl; ++ ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.core.xml.io.UnmarshallingException; ++import org.opensaml.xmlsec.encryption.AgreementMethod; ++import org.opensaml.xmlsec.encryption.KANonce; ++import org.opensaml.xmlsec.encryption.KeyDerivationMethod; ++import org.opensaml.xmlsec.encryption.OriginatorKeyInfo; ++import org.opensaml.xmlsec.encryption.RecipientKeyInfo; ++import org.w3c.dom.Attr; ++ ++/** ++ * ++ */ ++public class KeyDerivationMethodUnmarshaller extends AbstractXMLEncryptionUnmarshaller { ++ ++ /** {@inheritDoc} */ ++ protected void processAttribute(XMLObject xmlObject, Attr attribute) throws UnmarshallingException { ++ ++ final KeyDerivationMethod kdm = (KeyDerivationMethod) xmlObject; ++ if (attribute.getLocalName().equals(KeyDerivationMethod.ALGORITHM_ATTRIBUTE_NAME)) { ++ kdm.setAlgorithm(attribute.getValue()); ++ attribute.getOwnerElement().setIdAttributeNode(attribute, true); ++ } ++ } ++ ++ /** {@inheritDoc} */ ++ protected void processChildElement(final XMLObject parentXMLObject, final XMLObject childXMLObject) ++ throws UnmarshallingException { ++ final KeyDerivationMethod am = (KeyDerivationMethod) parentXMLObject; ++ am.getUnknownXMLObjects().add(childXMLObject); ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/keyinfo/impl/ECDHKeyInfoGeneratorFactory.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/keyinfo/impl/ECDHKeyInfoGeneratorFactory.java new file mode 100644 index 0000000..0a0dd7b --- /dev/null +++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/keyinfo/impl/ECDHKeyInfoGeneratorFactory.java @@ -0,0 +1,125 @@ -+/* -+ * Licensed to the University Corporation for Advanced Internet Development, -+ * Inc. (UCAID) under one or more contributor license agreements. See the -+ * NOTICE file distributed with this work for additional information regarding -+ * copyright ownership. The UCAID licenses this file to You under the Apache -+ * License, Version 2.0 (the "License"); you may not use this file except in -+ * compliance with the License. You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package org.opensaml.xmlsec.keyinfo.impl; -+ -+import java.util.List; -+ -+import javax.annotation.Nonnull; -+ -+import org.opensaml.core.xml.XMLObject; -+import org.opensaml.core.xml.XMLObjectBuilder; -+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; -+import org.opensaml.security.SecurityException; -+import org.opensaml.security.credential.BasicCredential; -+import org.opensaml.security.credential.Credential; -+import org.opensaml.security.x509.ECDHCredential; -+import org.opensaml.xmlsec.encryption.AgreementMethod; -+import org.opensaml.xmlsec.encryption.ConcatKDFParams; -+import org.opensaml.xmlsec.encryption.KeyDerivationMethod; -+import org.opensaml.xmlsec.encryption.OriginatorKeyInfo; -+import org.opensaml.xmlsec.encryption.RecipientKeyInfo; -+import org.opensaml.xmlsec.encryption.impl.AgreementMethodBuilder; -+import org.opensaml.xmlsec.encryption.impl.ConcatKDFParamsBuilder; -+import org.opensaml.xmlsec.encryption.impl.KeyDerivationMethodBuilder; -+import org.opensaml.xmlsec.encryption.impl.OriginatorKeyInfoBuilder; -+import org.opensaml.xmlsec.encryption.impl.RecipientKeyInfoBuilder; -+import org.opensaml.xmlsec.encryption.support.EncryptionConstants; -+import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator; -+import org.opensaml.xmlsec.signature.DigestMethod; -+import org.opensaml.xmlsec.signature.KeyInfo; -+import org.opensaml.xmlsec.signature.X509Data; -+import org.opensaml.xmlsec.signature.impl.DigestMethodBuilder; -+import org.opensaml.xmlsec.signature.impl.KeyInfoBuilder; -+ -+/** -+ * -+ */ -+public class ECDHKeyInfoGeneratorFactory extends X509KeyInfoGeneratorFactory { -+ -+ /** {@inheritDoc} */ -+ public boolean handles(@Nonnull final Credential credential) { -+ return credential instanceof ECDHCredential; -+ } -+ -+ /** {@inheritDoc} */ -+ public Class getCredentialType() { -+ return ECDHCredential.class; -+ } -+ -+ /** {@inheritDoc} */ -+ @Nonnull public KeyInfoGenerator newInstance() { -+ // TODO lock options during cloning ? -+ final X509Options newOptions = super.getOptions().clone(); -+ return new ECDHKeyInfoGenerator(newOptions); -+ } -+ -+ public class ECDHKeyInfoGenerator extends X509KeyInfoGenerator { -+ -+ /** -+ * Constructor. -+ * -+ * @param newOptions -+ */ -+ protected ECDHKeyInfoGenerator(X509Options newOptions) { -+ super(newOptions); -+ } -+ -+ /** {@inheritDoc} */ -+ public KeyInfo generate(Credential credential) throws SecurityException { -+ -+ ECDHCredential ecdhCredential = (ECDHCredential) credential; -+ -+ AgreementMethod am = new AgreementMethodBuilder().buildObject(); -+ am.setAlgorithm(EncryptionConstants.ALGO_ID_KEYAGREEMENT_ECDH_ES); -+ -+ KeyDerivationMethod kdm = new KeyDerivationMethodBuilder().buildObject(); -+ kdm.setAlgorithm(EncryptionConstants.ALGO_ID_KEYDERIVATION_CONCAT); -+ ConcatKDFParams kdfParams = new ConcatKDFParamsBuilder().buildObject(); -+ kdfParams.setAlgorithmID(ecdhCredential.getConcatKDF().getAlgorithmID()); -+ kdfParams.setPartyUInfo(ecdhCredential.getConcatKDF().getPartyUInfo()); -+ kdfParams.setPartyVInfo(ecdhCredential.getConcatKDF().getPartyVInfo()); -+ kdfParams.setSuppPrivInfo(ecdhCredential.getConcatKDF().getSuppPrivInfo()); -+ kdfParams.setSuppPubInfo(ecdhCredential.getConcatKDF().getSuppPubInfo()); -+ DigestMethod dm = new DigestMethodBuilder().buildObject(); -+ dm.setAlgorithm(ecdhCredential.getConcatKDF().getDigestMethod().getAlgorithm()); -+ kdfParams.setDigestMethod(dm); -+ kdm.getUnknownXMLObjects().add(kdfParams); -+ am.getUnknownXMLObjects().add(kdm); -+ -+ OriginatorKeyInfo oki = new OriginatorKeyInfoBuilder().buildObject(); -+ BasicCredential tempCredential = new BasicCredential(ecdhCredential.getSenderPubKey()); -+ processPublicKey(oki, tempCredential); -+ am.setOriginatorKeyInfo(oki); -+ -+ RecipientKeyInfo rki = new RecipientKeyInfoBuilder().buildObject(); -+ XMLObjectBuilder x509DataBuilder = XMLObjectProviderRegistrySupport.getBuilderFactory() -+ .getBuilderOrThrow(X509Data.DEFAULT_ELEMENT_NAME); -+ final X509Data x509Data = x509DataBuilder.buildObject(X509Data.DEFAULT_ELEMENT_NAME); -+ processEntityCertificate(rki, x509Data, ecdhCredential); -+ final List x509DataChildren = x509Data.getOrderedChildren(); -+ if (x509DataChildren != null && x509DataChildren.size() > 0) { -+ rki.getX509Datas().add(x509Data); -+ } -+ am.setRecipientKeyInfo(rki); -+ -+ KeyInfo keyInfo = new KeyInfoBuilder().buildObject(); -+ keyInfo.getAgreementMethods().add(am); -+ return keyInfo; -+ } -+ } -+} ++/* ++ * Licensed to the University Corporation for Advanced Internet Development, ++ * Inc. (UCAID) under one or more contributor license agreements. See the ++ * NOTICE file distributed with this work for additional information regarding ++ * copyright ownership. The UCAID licenses this file to You under the Apache ++ * License, Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++package org.opensaml.xmlsec.keyinfo.impl; ++ ++import java.util.List; ++ ++import javax.annotation.Nonnull; ++ ++import org.opensaml.core.xml.XMLObject; ++import org.opensaml.core.xml.XMLObjectBuilder; ++import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; ++import org.opensaml.security.SecurityException; ++import org.opensaml.security.credential.BasicCredential; ++import org.opensaml.security.credential.Credential; ++import org.opensaml.security.x509.ECDHCredential; ++import org.opensaml.xmlsec.encryption.AgreementMethod; ++import org.opensaml.xmlsec.encryption.ConcatKDFParams; ++import org.opensaml.xmlsec.encryption.KeyDerivationMethod; ++import org.opensaml.xmlsec.encryption.OriginatorKeyInfo; ++import org.opensaml.xmlsec.encryption.RecipientKeyInfo; ++import org.opensaml.xmlsec.encryption.impl.AgreementMethodBuilder; ++import org.opensaml.xmlsec.encryption.impl.ConcatKDFParamsBuilder; ++import org.opensaml.xmlsec.encryption.impl.KeyDerivationMethodBuilder; ++import org.opensaml.xmlsec.encryption.impl.OriginatorKeyInfoBuilder; ++import org.opensaml.xmlsec.encryption.impl.RecipientKeyInfoBuilder; ++import org.opensaml.xmlsec.encryption.support.EncryptionConstants; ++import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator; ++import org.opensaml.xmlsec.signature.DigestMethod; ++import org.opensaml.xmlsec.signature.KeyInfo; ++import org.opensaml.xmlsec.signature.X509Data; ++import org.opensaml.xmlsec.signature.impl.DigestMethodBuilder; ++import org.opensaml.xmlsec.signature.impl.KeyInfoBuilder; ++ ++/** ++ * ++ */ ++public class ECDHKeyInfoGeneratorFactory extends X509KeyInfoGeneratorFactory { ++ ++ /** {@inheritDoc} */ ++ public boolean handles(@Nonnull final Credential credential) { ++ return credential instanceof ECDHCredential; ++ } ++ ++ /** {@inheritDoc} */ ++ public Class getCredentialType() { ++ return ECDHCredential.class; ++ } ++ ++ /** {@inheritDoc} */ ++ @Nonnull public KeyInfoGenerator newInstance() { ++ // TODO lock options during cloning ? ++ final X509Options newOptions = super.getOptions().clone(); ++ return new ECDHKeyInfoGenerator(newOptions); ++ } ++ ++ public class ECDHKeyInfoGenerator extends X509KeyInfoGenerator { ++ ++ /** ++ * Constructor. ++ * ++ * @param newOptions ++ */ ++ protected ECDHKeyInfoGenerator(X509Options newOptions) { ++ super(newOptions); ++ } ++ ++ /** {@inheritDoc} */ ++ public KeyInfo generate(Credential credential) throws SecurityException { ++ ++ ECDHCredential ecdhCredential = (ECDHCredential) credential; ++ ++ AgreementMethod am = new AgreementMethodBuilder().buildObject(); ++ am.setAlgorithm(EncryptionConstants.ALGO_ID_KEYAGREEMENT_ECDH_ES); ++ ++ KeyDerivationMethod kdm = new KeyDerivationMethodBuilder().buildObject(); ++ kdm.setAlgorithm(EncryptionConstants.ALGO_ID_KEYDERIVATION_CONCAT); ++ ConcatKDFParams kdfParams = new ConcatKDFParamsBuilder().buildObject(); ++ kdfParams.setAlgorithmID(ecdhCredential.getConcatKDF().getAlgorithmID()); ++ kdfParams.setPartyUInfo(ecdhCredential.getConcatKDF().getPartyUInfo()); ++ kdfParams.setPartyVInfo(ecdhCredential.getConcatKDF().getPartyVInfo()); ++ kdfParams.setSuppPrivInfo(ecdhCredential.getConcatKDF().getSuppPrivInfo()); ++ kdfParams.setSuppPubInfo(ecdhCredential.getConcatKDF().getSuppPubInfo()); ++ DigestMethod dm = new DigestMethodBuilder().buildObject(); ++ dm.setAlgorithm(ecdhCredential.getConcatKDF().getDigestMethod().getAlgorithm()); ++ kdfParams.setDigestMethod(dm); ++ kdm.getUnknownXMLObjects().add(kdfParams); ++ am.getUnknownXMLObjects().add(kdm); ++ ++ OriginatorKeyInfo oki = new OriginatorKeyInfoBuilder().buildObject(); ++ BasicCredential tempCredential = new BasicCredential(ecdhCredential.getSenderPubKey()); ++ processPublicKey(oki, tempCredential); ++ am.setOriginatorKeyInfo(oki); ++ ++ RecipientKeyInfo rki = new RecipientKeyInfoBuilder().buildObject(); ++ XMLObjectBuilder x509DataBuilder = XMLObjectProviderRegistrySupport.getBuilderFactory() ++ .getBuilderOrThrow(X509Data.DEFAULT_ELEMENT_NAME); ++ final X509Data x509Data = x509DataBuilder.buildObject(X509Data.DEFAULT_ELEMENT_NAME); ++ processEntityCertificate(rki, x509Data, ecdhCredential); ++ final List x509DataChildren = x509Data.getOrderedChildren(); ++ if (x509DataChildren != null && x509DataChildren.size() > 0) { ++ rki.getX509Datas().add(x509Data); ++ } ++ am.setRecipientKeyInfo(rki); ++ ++ KeyInfo keyInfo = new KeyInfoBuilder().buildObject(); ++ keyInfo.getAgreementMethods().add(am); ++ return keyInfo; ++ } ++ } ++} diff --git a/opensaml-xmlsec-impl/src/main/resources/encryption-config.xml b/opensaml-xmlsec-impl/src/main/resources/encryption-config.xml index 9ded3a1..549447b 100644 --- a/opensaml-xmlsec-impl/src/main/resources/encryption-config.xml diff --git a/pom.xml b/pom.xml index b2420488..5252a0c8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,12 +9,13 @@ ~ limitations under the Licence. --> + 4.0.0 de.governikus.eumw eumw - 3.1.2 + 3.2.0 pom EU Middleware @@ -37,7 +38,7 @@ https://hg.govkg.de/Autent/eumw scm:hg:https://hg.govkg.de/Autent/eumw - eumw-3.1.2 + eumw-3.2.0 @@ -81,81 +82,73 @@ UTF-8 - 11 + 17 - 11 + 17 - - 1.66 - - 2.1.2 + 1.77 8.4.0 - 2.1.0 - 4.0.1 - - 2.3 - 2.3.4 - - - 3.5.6 - 2.7.13 - - 3.0.15.RELEASE - 3.2.1 + 5.0.0 + 3.0.0 + 4.0.0 + 4.0.0 + + 4.0.3 + + 3.1.6 + 3.3.0 6.5.1 - 9.5 - 4.8.162 - 1.16.0 + 9.6 + 4.8.165 1.5 - 2.13.0 - 1.10.0 - 3.13.0 - 32.1.2-jre + 2.15.0 + 1.11.0 + 3.14.0 + 32.1.3-jre 1.4.200 + + 4.5.14 4.2.0 - 2.15.2 + 2.16.0 2.0.1 - - 2.1.0 + 3.0.0 1.11.1 - - 2.3.8 - 0.7.39 + 4.0.2 + 4.0.4 + 0.7.40 2.2.14 3.0.2 - 3.0.18 + 4.0.15 3.6.7 - - 9.0.82 + 2.2 - 1.18.28 + 1.18.30 - 2.20.0 - 1.7.36 + 2.22.0 + 2.0.9 2.70.0 - 4.5.14 - 5.10.0 + 5.10.1 5.12.0 1.3.0 - 8.4.0 + 9.0.6 - 0.47 + 0.50 6.4.2 - 1.0.4 - 5.3.1 - 3.7.0 + 1.0.7 + 5.3.2 + 3.7.1 @@ -163,9 +156,9 @@ 0.43.0 1.0-beta-7 0.8.4 - 0.14.0 + 0.15.3 3.0 - 2.6 + 4.0.1 2.0.0 3.2.0 3.0.0 @@ -183,15 +176,26 @@ 3.7 3.0.1 2.22.2 + + + + 4.0.1 + 3.0.1 + 1.16.0 - org.codehaus.mojo + org.jvnet.jaxb + jaxb-maven-plugin + ${version.jvnet.jaxb} + + + com.sun.xml.ws jaxws-maven-plugin - ${version.jaxws-maven-plugin} + ${version.jaxws.maven.plugin} -Djavax.xml.accessExternalSchema=all @@ -409,7 +413,7 @@ - [11, 12) + 17 @@ -442,6 +446,36 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + --add-exports + java.base/sun.security.util=ALL-UNNAMED + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens java.base/sun.security.util=ALL-UNNAMED + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + java.base/sun.security.util + + + + @@ -484,6 +518,24 @@ junit-vintage-engine test + + + + + com.sun.xml.ws + jaxws-rt + ${version.jaxws-rt} + + + org.jvnet.jaxb + jaxb-plugins-runtime + ${version.jvnet.jaxb} + + + commons-codec + commons-codec + ${version.commons.codec} + @@ -581,16 +633,7 @@ - - org.thymeleaf - thymeleaf-spring5 - ${version.thymeleaf} - - - org.thymeleaf - thymeleaf - ${version.thymeleaf} - + nz.net.ultraq.thymeleaf thymeleaf-layout-dialect @@ -690,9 +733,9 @@ - se.litsec.eidas - eidas-opensaml4 - ${version.eidas-opensaml4} + se.swedenconnect.opensaml + opensaml-eidas + ${version.opensaml-eidas} @@ -703,7 +746,13 @@ org.opensaml - opensaml-core + opensaml-core-api + ${version.opensaml} + + + + org.opensaml + opensaml-core-impl ${version.opensaml} @@ -743,12 +792,6 @@ ${version.opensaml} - - org.apache.velocity - velocity-engine-core - ${version.velocity} - - net.shibboleth.utilities java-support @@ -757,20 +800,24 @@ org.bouncycastle - bcprov-jdk15on + bcprov-jdk18on ${version.bouncycastle} org.bouncycastle - bcpkix-jdk15on + bcpkix-jdk18on ${version.bouncycastle} org.bouncycastle - bctls-jdk15on + bctls-jdk18on + ${version.bouncycastle} + + + org.bouncycastle + bcutil-jdk18on ${version.bouncycastle} - org.jvnet.jaxb2_commons jaxb2-basics-runtime @@ -880,21 +927,10 @@ ${version.jmrtd} - - - org.apache.tomcat.embed - tomcat-embed-core - ${version.tomcat} - - - org.apache.tomcat.embed - tomcat-embed-el - ${version.tomcat} - - org.apache.tomcat.embed - tomcat-embed-websocket - ${version.tomcat} + org.yaml + snakeyaml + ${version.snakeyaml} @@ -954,7 +990,7 @@ ${version.httpclient} - org.codehaus.groovy + org.apache.groovy groovy ${version.groovy} diff --git a/poseidas/pom.xml b/poseidas/pom.xml index 1ccc531f..861583ff 100644 --- a/poseidas/pom.xml +++ b/poseidas/pom.xml @@ -14,7 +14,7 @@ de.governikus.eumw eumw - 3.1.2 + 3.2.0 poseidas @@ -54,11 +54,11 @@ org.bouncycastle - bcprov-jdk15on + bcprov-jdk18on org.bouncycastle - bcpkix-jdk15on + bcpkix-jdk18on org.jvnet.jaxb2_commons @@ -132,7 +132,7 @@ org.thymeleaf.extras - thymeleaf-extras-springsecurity5 + thymeleaf-extras-springsecurity6 @@ -177,8 +177,8 @@ ${project.name} - org.jvnet.jaxb2.maven2 - maven-jaxb2-plugin + org.jvnet.jaxb + jaxb-maven-plugin xjc-ecard @@ -225,15 +225,21 @@ true - org.jvnet.jaxb2_commons - jaxb2-value-constructor - ${version.jaxb2-value-constructor} - - - org.jvnet.jaxb2_commons - jaxb2-basics - ${version.jaxb2-basics} + org.jvnet.jaxb + jaxb-plugins + ${version.jvnet.jaxb} + + + + + + + + + + + @@ -273,7 +279,7 @@
- org.codehaus.mojo + com.sun.xml.ws jaxws-maven-plugin diff --git a/poseidas/src/main/java/de/governikus/eumw/eidasmiddleware/eid/RequestingServiceProvider.java b/poseidas/src/main/java/de/governikus/eumw/eidasmiddleware/eid/RequestingServiceProvider.java index fa065440..9937008d 100644 --- a/poseidas/src/main/java/de/governikus/eumw/eidasmiddleware/eid/RequestingServiceProvider.java +++ b/poseidas/src/main/java/de/governikus/eumw/eidasmiddleware/eid/RequestingServiceProvider.java @@ -13,7 +13,7 @@ import lombok.Getter; import lombok.Setter; -import se.litsec.eidas.opensaml.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/POSeIDASSecurityConfig.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/POSeIDASSecurityConfig.java index 6b3def09..5d1dbc43 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/POSeIDASSecurityConfig.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/POSeIDASSecurityConfig.java @@ -9,15 +9,15 @@ package de.governikus.eumw.poseidas; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; import org.springframework.http.HttpMethod; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import de.governikus.eumw.eidascommon.ContextPaths; @@ -28,69 +28,67 @@ * @author bpr */ @EnableWebSecurity +@Configuration public class POSeIDASSecurityConfig { - @Autowired - PasswordFileAuthenticationProvider authenticationProvider; - /** * This security configuration limits the access to the web admin. Static resources and the login page can be accessed * without authentication, everything else must be authenticated. */ - @Configuration - @Order(1) - public static class WebAdminSecurity extends WebSecurityConfigurerAdapter + @Bean + public SecurityFilterChain adminUiSecurityFilterChain(HttpSecurity httpSecurity, + PasswordFileAuthenticationProvider authenticationProvider, + HandlerMappingIntrospector introspector) + throws Exception { - @Override - protected void configure(HttpSecurity http) throws Exception - { - http.antMatcher(ContextPaths.ADMIN_CONTEXT_PATH + "/**"); - http.authorizeRequests(authorize -> authorize.mvcMatchers(ContextPaths.ADMIN_CONTEXT_PATH + "/webjars/**", - ContextPaths.ADMIN_CONTEXT_PATH + "/css/**", - ContextPaths.ADMIN_CONTEXT_PATH + "/images/**", - ContextPaths.ADMIN_CONTEXT_PATH + "/js/**", - ContextPaths.ADMIN_CONTEXT_PATH + "/setNewPassword") - .permitAll() - .mvcMatchers(ContextPaths.ADMIN_CONTEXT_PATH + "/**") - .authenticated()); - http.formLogin() - .loginPage(ContextPaths.ADMIN_CONTEXT_PATH + "/login") - .defaultSuccessUrl(ContextPaths.ADMIN_CONTEXT_PATH + "/dashboard") - .permitAll() - .and() - .logout() - .logoutRequestMatcher(new AntPathRequestMatcher(ContextPaths.ADMIN_CONTEXT_PATH + "/logout", - HttpMethod.GET.name())) - .permitAll() - .and() - .headers() - .contentSecurityPolicy("script-src 'self'"); - } + + httpSecurity.securityMatcher(ContextPaths.ADMIN_CONTEXT_PATH + "/**"); + httpSecurity.authorizeHttpRequests(matcherRegistry -> matcherRegistry.requestMatchers(new MvcRequestMatcher(introspector, + ContextPaths.ADMIN_CONTEXT_PATH + + "/webjars/**"), + new MvcRequestMatcher(introspector, + ContextPaths.ADMIN_CONTEXT_PATH + + "/css/**"), + new MvcRequestMatcher(introspector, + ContextPaths.ADMIN_CONTEXT_PATH + + "/images/**"), + new MvcRequestMatcher(introspector, + ContextPaths.ADMIN_CONTEXT_PATH + + "/js/**"), + new MvcRequestMatcher(introspector, + ContextPaths.ADMIN_CONTEXT_PATH + + "/setNewPassword")) + .permitAll() + .requestMatchers(new MvcRequestMatcher(introspector, ContextPaths.ADMIN_CONTEXT_PATH + + "/**")) + .authenticated()); + + httpSecurity.formLogin(configurer -> configurer.loginPage(ContextPaths.ADMIN_CONTEXT_PATH + "/login") + .defaultSuccessUrl(ContextPaths.ADMIN_CONTEXT_PATH + "/dashboard") + .permitAll()); + httpSecurity.logout(configurer -> configurer.logoutRequestMatcher(new AntPathRequestMatcher(ContextPaths.ADMIN_CONTEXT_PATH + + "/logout", + HttpMethod.GET.name())) + .permitAll()); + httpSecurity.headers(configurer -> configurer.contentSecurityPolicy(contentSecurityPolicyConfig -> contentSecurityPolicyConfig.policyDirectives("script-src 'self'"))); + httpSecurity.authenticationProvider(authenticationProvider); + + return httpSecurity.build(); } /** * Spring security for the eIDAS (SAML) part. No authentication is necessary. */ - @Configuration - @Order(2) - public static class EidasSecurity extends WebSecurityConfigurerAdapter + @Bean + public SecurityFilterChain eidasSecurityFilterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity.securityMatcher(ContextPaths.EIDAS_CONTEXT_PATH + "/**"); + httpSecurity.authorizeHttpRequests(matcherRegistry -> matcherRegistry.anyRequest().permitAll()); + httpSecurity.csrf(configurer -> configurer.disable()); - @Override - protected void configure(HttpSecurity http) throws Exception - { - http.antMatcher(ContextPaths.EIDAS_CONTEXT_PATH + "/**"); - http.authorizeRequests(authorize -> authorize.anyRequest().permitAll()); - http.csrf().disable(); - } - + return httpSecurity.build(); } - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) - { - auth.authenticationProvider(authenticationProvider); - } } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/DomainParameterInfo.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/DomainParameterInfo.java index c674daec..46680a7f 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/DomainParameterInfo.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/DomainParameterInfo.java @@ -14,14 +14,23 @@ /** - * Abstract class for domain parameter infos, currently extended by - * {@link ChipAuthenticationDomainParameterInfo} and {@link PACEDomainParameterInfo}. + * Abstract class for domain parameter infos. * * @author Arne Stahlbock, ast@bos-bremen.de */ -public abstract class DomainParameterInfo extends SecurityInfo implements GeneralDomainParameterInfo +public abstract class DomainParameterInfo extends SecurityInfo { + /** + * Current lowest domain parameter ID. + */ + public static final int MIN_DOMAIN_PARAMETER_ID = 8; + + /** + * Current highest domain parameter ID. + */ + public static final int MAX_DOMAIN_PARAMETER_ID = 18; + /** * Reference to the domainParameter child element. */ diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/GeneralDomainParameterInfo.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/GeneralDomainParameterInfo.java deleted file mode 100644 index 4e2170a5..00000000 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/GeneralDomainParameterInfo.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -package de.governikus.eumw.poseidas.cardbase.asn1.npa.si; - -/** - * Marker interface for anything that contains domain parameter infos. That could be a class containing all - * the parameters, another alternative is a class containing simply an ID for a set of standard parameters. - * - * @author Arne Stahlbock, ast@bos-bremen.de - */ -public interface GeneralDomainParameterInfo -{ - - /** - * Current lowest domain parameter ID. - */ - public static final int MIN_DOMAIN_PARAMETER_ID = 8; - - /** - * Current highest domain parameter ID. - */ - public static final int MAX_DOMAIN_PARAMETER_ID = 18; -} diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/StandardDomainParameterInfo.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/StandardDomainParameterInfo.java deleted file mode 100644 index 2777cd77..00000000 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/asn1/npa/si/StandardDomainParameterInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. - */ - -package de.governikus.eumw.poseidas.cardbase.asn1.npa.si; - -import de.governikus.eumw.poseidas.cardbase.AssertUtil; - - -/** - * Class for a standard set of domain parameter infos referenced by an ID. - * - * @author Arne Stahlbock, ast@bos-bremen.de - */ -public class StandardDomainParameterInfo implements GeneralDomainParameterInfo -{ - - /** - * ID of domain parameters. - */ - private final Integer dpiID; - - /** - * Constructor. - * - * @param dpiID ID of domain parameters - * @throws IllegalArgumentException if given ID null or having unknown value - */ - public StandardDomainParameterInfo(Integer dpiID) - { - AssertUtil.notNull(dpiID, "domain parameter ID"); - if (dpiID < MIN_DOMAIN_PARAMETER_ID || dpiID > MAX_DOMAIN_PARAMETER_ID) - { - throw new IllegalArgumentException("unknown domain parameter ID"); - } - this.dpiID = dpiID; - } - - /** - * Gets domain parameter ID. - * - * @return domain parameter ID - */ - public Integer getdpiID() - { - return this.dpiID; - } -} diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/constants/OIDConstants.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/constants/OIDConstants.java index 8385ead8..f2f3afca 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/constants/OIDConstants.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/constants/OIDConstants.java @@ -29,6 +29,21 @@ public final class OIDConstants */ public static final OID OID_EC_PUBLIC_KEY = new OID("1.2.840.10045.2.1"); + /** + * OID of signature algorithm ECDSA with SHA-256. + */ + public static final OID OID_ECDSA_SHA256 = new OID("1.2.840.10045.4.3.2"); + + /** + * OID of signature algorithm ECDSA with SHA-384. + */ + public static final OID OID_ECDSA_SHA384 = new OID("1.2.840.10045.4.3.3"); + + /** + * OID of signature algorithm ECDSA with SHA-512. + */ + public static final OID OID_ECDSA_SHA512 = new OID("1.2.840.10045.4.3.4"); + /** * OID of BSI: 0.4.0.127.0.7. */ diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/HashConstants.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/HashConstants.java index 534c6eb3..b8a12cf8 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/HashConstants.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/HashConstants.java @@ -23,7 +23,7 @@ * @author Jens Wothe, jw@bos-bremen.de */ @UtilityClass -final class HashConstants +public final class HashConstants { /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/ec/ECUtil.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/ec/ECUtil.java index 070679ae..acab430e 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/ec/ECUtil.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/ec/ECUtil.java @@ -28,8 +28,6 @@ import de.governikus.eumw.poseidas.cardbase.asn1.npa.SecurityInfos; import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.AlgorithmIdentifier; import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.DomainParameterInfo; -import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.GeneralDomainParameterInfo; -import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.StandardDomainParameterInfo; import de.governikus.eumw.poseidas.cardbase.constants.OIDConstants; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -46,33 +44,24 @@ public class ECUtil { /** - * Builds {@link ECParameterSpec} object using the different variants of domain parameter information - * structures contained in EF.CardAccess. + * Builds {@link ECParameterSpec} object using the different variants of domain parameter information structures + * contained in EF.CardAccess. * - * @param paramInfo domain parameter object, null not permitted, currently accepted types are - * {@link DomainParameterInfo} and {@link StandardDomainParameterInfo} + * @param paramInfo domain parameter object, null not permitted * @return {@link ECParameterSpec} object containing given domain parameters * @throws IllegalArgumentException if paramInfo null or unknown type * @throws IOException */ - public static ECParameterSpec parameterSpecFromDomainParameters(GeneralDomainParameterInfo paramInfo) - throws IOException + public static ECParameterSpec parameterSpecFromDomainParameters(DomainParameterInfo paramInfo) throws IOException { AssertUtil.notNull(paramInfo, "domain parameter info"); - if (paramInfo instanceof DomainParameterInfo) - { - AlgorithmIdentifier ai = ((DomainParameterInfo)paramInfo).getDomainParameter(); - if (OIDConstants.OID_STANDARDIZED_DOMAIN_PARAMETERS.equals(ai.getAlgorithm())) - { - return parameterSpecFromCurveID(ai.getParameterID()); - } - return parameterSpecFromAlgorithmIdentifier(ai); - } - if (paramInfo instanceof StandardDomainParameterInfo) + + AlgorithmIdentifier ai = paramInfo.getDomainParameter(); + if (OIDConstants.OID_STANDARDIZED_DOMAIN_PARAMETERS.equals(ai.getAlgorithm())) { - return parameterSpecFromCurveID(((StandardDomainParameterInfo)paramInfo).getdpiID()); + return parameterSpecFromCurveID(ai.getParameterID()); } - throw new IllegalArgumentException("unknown domain parameter info"); + return parameterSpecFromAlgorithmIdentifier(ai); } /** @@ -83,8 +72,7 @@ public static ECParameterSpec parameterSpecFromDomainParameters(GeneralDomainPar * @throws IllegalArgumentException if algorithm identifier null * @throws IOException */ - public static ECParameterSpec parameterSpecFromAlgorithmIdentifier(AlgorithmIdentifier ai) - throws IOException + private static ECParameterSpec parameterSpecFromAlgorithmIdentifier(AlgorithmIdentifier ai) throws IOException { AssertUtil.notNull(ai, "algorithm identifier"); if (!OIDConstants.OID_EC_PUBLIC_KEY.equals(ai.getAlgorithm())) @@ -208,8 +196,7 @@ private static ECParameterSpec buildParameterSpec(BigInteger primeModulus, */ private static ECParameterSpec parameterSpecFromCurveID(int id) { - if (id < GeneralDomainParameterInfo.MIN_DOMAIN_PARAMETER_ID - || id > GeneralDomainParameterInfo.MAX_DOMAIN_PARAMETER_ID) + if (id < DomainParameterInfo.MIN_DOMAIN_PARAMETER_ID || id > DomainParameterInfo.MAX_DOMAIN_PARAMETER_ID) { throw new IllegalArgumentException("given curve ID currently not specified"); } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandler.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandler.java index 60559f73..7df7fe3f 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandler.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandler.java @@ -21,7 +21,7 @@ import java.security.spec.InvalidKeySpecException; import de.governikus.eumw.poseidas.cardbase.asn1.OID; -import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.GeneralDomainParameterInfo; +import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.DomainParameterInfo; /** @@ -35,7 +35,7 @@ public interface KeyHandler /** * Generates a key pair. * - * @param params {@link GeneralDomainParameterInfo} to use in generation, null not permitted + * @param params {@link DomainParameterInfo} to use in generation, null not permitted * @return generated {@link KeyPair} * @throws IllegalArgumentException if params null * @throws IOException @@ -43,7 +43,7 @@ public interface KeyHandler * @throws NoSuchProviderException * @throws NoSuchAlgorithmException */ - public abstract KeyPair generateKeyPair(GeneralDomainParameterInfo params) throws + public abstract KeyPair generateKeyPair(DomainParameterInfo params) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException; /** @@ -62,7 +62,7 @@ public abstract KeyPair generateKeyPair(AlgorithmParameterSpec spec) throws /** * Builds {@link PublicKey} object from byte-array encoding the key. * - * @param params domain parameters as {@link GeneralDomainParameterInfo}, null not permitted + * @param params domain parameters as {@link DomainParameterInfo}, null not permitted * @param keyBytes key data as byte-array, null or empty not permitted * @return generated {@link PublicKey} * @throws IllegalArgumentException if any argument null or if keyBytes empty @@ -71,7 +71,7 @@ public abstract KeyPair generateKeyPair(AlgorithmParameterSpec spec) throws * @throws NoSuchProviderException * @throws NoSuchAlgorithmException */ - public abstract PublicKey buildKeyFromBytes(GeneralDomainParameterInfo params, byte[] keyBytes) + public abstract PublicKey buildKeyFromBytes(DomainParameterInfo params, byte[] keyBytes) throws IOException; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandlerEC.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandlerEC.java index 40a1af32..05087237 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandlerEC.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/crypto/key/KeyHandlerEC.java @@ -30,7 +30,7 @@ import de.governikus.eumw.poseidas.cardbase.ByteUtil; import de.governikus.eumw.poseidas.cardbase.asn1.ASN1; import de.governikus.eumw.poseidas.cardbase.asn1.OID; -import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.GeneralDomainParameterInfo; +import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.DomainParameterInfo; import de.governikus.eumw.poseidas.cardbase.crypto.ec.ECMath; import de.governikus.eumw.poseidas.cardbase.crypto.ec.ECPublicKeyImpl; import de.governikus.eumw.poseidas.cardbase.crypto.ec.ECUtil; @@ -66,7 +66,7 @@ public KeyHandlerEC(int parameter) /** {@inheritDoc} */ @Override - public KeyPair generateKeyPair(GeneralDomainParameterInfo params) + public KeyPair generateKeyPair(DomainParameterInfo params) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { AssertUtil.notNull(params, "domain parameter info"); @@ -95,7 +95,7 @@ public KeyPair generateKeyPair(AlgorithmParameterSpec spec) /** {@inheritDoc} */ @Override - public PublicKey buildKeyFromBytes(GeneralDomainParameterInfo params, byte[] keyBytes) throws IOException + public PublicKey buildKeyFromBytes(DomainParameterInfo params, byte[] keyBytes) throws IOException { AssertUtil.notNull(params, "domain parameter info"); AssertUtil.notNullOrEmpty(keyBytes, "key bytes"); diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelector.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelector.java index fdfdd645..d9980d90 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelector.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelector.java @@ -20,7 +20,6 @@ import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.ChipAuthenticationInfo; import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.ChipAuthenticationPublicKeyInfo; import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.DomainParameterInfo; -import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.GeneralDomainParameterInfo; import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.PACEDomainParameterInfo; import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.PACEInfo; import de.governikus.eumw.poseidas.cardbase.asn1.npa.si.TerminalAuthenticationInfo; @@ -42,26 +41,23 @@ public final class InfoSelector * * @param setCADomainParameterInfos set of available {@link ChipAuthenticationDomainParameterInfo}, null * or empty not permitted - * @return selected {@link ChipAuthenticationDomainParameterInfo} + * @return selected {@link ChipAuthenticationDomainParameterInfo}, null if no acceptable selection + * possible * @throws IllegalArgumentException if given set null or empty */ private static ChipAuthenticationDomainParameterInfo selectCADomainParameterInfo(Collection setCADomainParameterInfos) { AssertUtil.notNullOrEmpty(setCADomainParameterInfos, "list of domain parameter info"); - // if only one element present, use it - if (setCADomainParameterInfos.size() == 1) - { - return setCADomainParameterInfos.iterator().next(); - } - - // otherwise, prefer standardized parameters + // only use standardized parameters in specified range for ( ChipAuthenticationDomainParameterInfo info : setCADomainParameterInfos ) { try { AlgorithmIdentifier ai = info.getDomainParameter(); - if (OIDConstants.OID_STANDARDIZED_DOMAIN_PARAMETERS.equals(ai.getAlgorithm())) + if (OIDConstants.OID_STANDARDIZED_DOMAIN_PARAMETERS.equals(ai.getAlgorithm()) + && ai.getParameterID() >= DomainParameterInfo.MIN_DOMAIN_PARAMETER_ID + && ai.getParameterID() <= DomainParameterInfo.MAX_DOMAIN_PARAMETER_ID) { return info; } @@ -71,9 +67,7 @@ private static ChipAuthenticationDomainParameterInfo selectCADomainParameterInfo // nothing } } - - // there are more than one, but no standardized parameters - return setCADomainParameterInfos.iterator().next(); + return null; } /** @@ -144,8 +138,8 @@ public static PACEInfo selectPACEInfo(Collection listPACEInfos) } // prefer standard domain parameters - if (pID != null && pID >= GeneralDomainParameterInfo.MIN_DOMAIN_PARAMETER_ID - && pID <= GeneralDomainParameterInfo.MAX_DOMAIN_PARAMETER_ID) + if (pID != null && pID >= DomainParameterInfo.MIN_DOMAIN_PARAMETER_ID + && pID <= DomainParameterInfo.MAX_DOMAIN_PARAMETER_ID) { return info; } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/CertificateUtil.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/CertificateUtil.java index 2d4f7edf..8b3e07eb 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/CertificateUtil.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/CertificateUtil.java @@ -167,7 +167,7 @@ public static Predicate findIssuerByAuthorityKeyIdentifier(byte { ASN1OctetString asn1OctetString = (ASN1OctetString)ASN1Primitive.fromByteArray(authorityKeyIdentifier); ASN1Sequence asn1Sequence = (ASN1Sequence)ASN1Primitive.fromByteArray(asn1OctetString.getOctets()); - ASN1OctetString reference = (ASN1OctetString)((ASN1TaggedObject)asn1Sequence.getObjectAt(0)).getObject(); + ASN1OctetString reference = (ASN1OctetString)((ASN1TaggedObject)asn1Sequence.getObjectAt(0)).getBaseObject(); ASN1OctetString outerOctetString = (ASN1OctetString)ASN1Primitive.fromByteArray(certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId())); ASN1OctetString actual = (ASN1OctetString)ASN1Primitive.fromByteArray(outerOctetString.getOctets()); diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CertificateRequest.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CertificateRequest.java index 814ec7dc..9d811948 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CertificateRequest.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CertificateRequest.java @@ -1,11 +1,10 @@ /* - * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except - * in compliance with the Licence. You may obtain a copy of the Licence at: - * http://joinup.ec.europa.eu/software/page/eupl Unless required by applicable law or agreed to in writing, - * software distributed under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS - * OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and - * limitations under the Licence. + * Copyright (c) 2020 Governikus KG. Licensed under the EUPL, Version 1.2 or as soon they will be approved by the + * European Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance + * with the Licence. You may obtain a copy of the Licence at: http://joinup.ec.europa.eu/software/page/eupl Unless + * required by applicable law or agreed to in writing, software distributed under the Licence is distributed on an + * "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the + * specific language governing permissions and limitations under the Licence. */ package de.governikus.eumw.poseidas.cardserver.certrequest; @@ -22,7 +21,6 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.spec.InvalidKeySpecException; -import java.util.Arrays; import de.governikus.eumw.poseidas.cardbase.AssertUtil; import de.governikus.eumw.poseidas.cardbase.ByteUtil; @@ -58,7 +56,7 @@ public class CertificateRequest extends AbstractASN1Encoder * @see CertificateRequestPath#getTag() * @see CertificateRequestPath#CV_CERTIFICATE */ - public CertificateRequest(byte[] valueBytes) throws IOException + CertificateRequest(byte[] valueBytes) throws IOException { super(CertificateRequestPath.AUTHENTICATION.getTag().toByteArray(), valueBytes); check(); @@ -71,30 +69,16 @@ public CertificateRequest(byte[] valueBytes) throws IOException * @throws IOException if reading of stream fails * @see ASN1#ASN1(InputStream, boolean) */ - CertificateRequest(InputStream stream) throws IOException + public CertificateRequest(InputStream stream) throws IOException { super(stream); check(); } - /** - * Constructor. - * - * @param stream stream with ASN.1 bytes - * @param close true, if stream is to be closed after reading - * @throws IOException if reading of stream fails - * @see ASN1#ASN1(InputStream, boolean) - */ - public CertificateRequest(InputStream stream, boolean close) throws IOException - { - super(stream, close); - check(); - } - private void check() { - if (!Arrays.equals(CertificateRequestPath.AUTHENTICATION.getTag().toByteArray(), getDTagBytes()) - && !Arrays.equals(CertificateRequestPath.CV_CERTIFICATE.getTag().toByteArray(), getDTagBytes())) + if (!CertificateRequestPath.AUTHENTICATION.getTag().equals(getDTag()) + && !CertificateRequestPath.CV_CERTIFICATE.getTag().equals(getDTag())) { throw new IllegalArgumentException("ASN.1 does not represent a certificate request"); } @@ -102,13 +86,13 @@ private void check() /** {@inheritDoc} */ @Override - public ASN1 getChildElementByPath(ASN1Path part) throws IOException + public ASN1 getChildElementByPath(ASN1Path path) throws IOException { - if (!CertificateRequestPath.class.isInstance(part)) + if (!(path instanceof CertificateRequestPath)) { throw new IllegalArgumentException("only CertificateRequestPath permitted"); } - return super.getChildElementByPath(part); + return super.getChildElementByPath(path); } /** @@ -124,15 +108,6 @@ ASN1 getRequestPart(CertificateRequestPath path) throws IOException return super.getChildElementByPath(path); } - /** {@inheritDoc} */ - @Override - public ASN1 decode(byte[] bytes) throws IOException - { - CertificateRequest result = new CertificateRequest(bytes); - super.decode(result); - return this; - } - /** * Signs certificate of request (mandatory). * @@ -153,24 +128,21 @@ public ASN1 decode(byte[] bytes) throws IOException * @throws UnrecoverableKeyException */ void signCVCBody(PublicKey publicKey, String alias) throws IOException, UnrecoverableKeyException, - InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, KeyStoreException, - CertificateException, SignatureException, InvalidKeySpecException, HSMException + InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, KeyStoreException, CertificateException, + SignatureException, InvalidKeySpecException, HSMException { AssertUtil.notNull(publicKey, "public key"); AssertUtil.notNullOrEmpty(alias, "alias"); - if (!OIDPublicKey.class.isInstance(publicKey)) + if (!(publicKey instanceof OIDPublicKey)) { throw new IllegalArgumentException("only " + OIDPublicKey.class + " permitted"); } this.setCVCPublicKey(publicKey); - byte[] body = ByteUtil.copy(this.getChildElementByPath(CertificateRequestPath.CV_CERTIFICATE_BODY) - .getEncoded()); + byte[] body = ByteUtil.copy(this.getChildElementByPath(CertificateRequestPath.CV_CERTIFICATE_BODY).getEncoded()); - HSMService hsm = ServiceRegistry.Util.getServiceRegistry() - .getService(HSMServiceFactory.class) - .getHSMService(); + HSMService hsm = ServiceRegistry.Util.getServiceRegistry().getService(HSMServiceFactory.class).getHSMService(); byte[] signed = hsm.sign(alias, ((OIDPublicKey)publicKey).getOID(), body); this.setCVCSignature(signed); } @@ -186,7 +158,7 @@ void signCVCBody(PublicKey publicKey, String alias) throws IOException, Unrecove private void setCVCPublicKey(PublicKey publicKey) throws IOException { AssertUtil.notNull(publicKey, "public key"); - if (!OIDPublicKey.class.isInstance(publicKey)) + if (!(publicKey instanceof OIDPublicKey)) { throw new IllegalArgumentException("only " + OIDPublicKey.class + " permitted"); } @@ -281,9 +253,17 @@ public synchronized boolean isSequence() public ECPublicKey getPublicKey() throws IOException { + CertificateRequest cr = this; + // if we have a CR without outer signature, we must create a full CR structure so that the getRequestPart method can + // work correctly + if (CertificateRequestPath.CV_CERTIFICATE.getTag().equals(getDTag())) + { + cr = new CertificateRequest(this.getEncoded()); + } + try { - return new ECPublicKey(this.getRequestPart(CertificateRequestPath.PUBLIC_KEY).getEncoded()); + return new ECPublicKey(cr.getRequestPart(CertificateRequestPath.PUBLIC_KEY).getEncoded()); } catch (NullPointerException e) { @@ -293,23 +273,17 @@ public ECPublicKey getPublicKey() throws IOException public String getHolderReferenceString() throws IOException { - try - { - return new String(this.getRequestPart(CertificateRequestPath.HOLDER_REFERENCE).getValue(), - StandardCharsets.UTF_8); - } - catch (NullPointerException e) + CertificateRequest cr = this; + // if we have a CR without outer signature, we must create a full CR structure so that the getRequestPart method can + // work correctly + if (CertificateRequestPath.CV_CERTIFICATE.getTag().equals(getDTag())) { - return null; + cr = new CertificateRequest(this.getEncoded()); } - } - public String getAuthorityReferenceString() throws IOException - { try { - return new String(this.getRequestPart(CertificateRequestPath.CA_REFERENCE).getValue(), - StandardCharsets.UTF_8); + return new String(cr.getRequestPart(CertificateRequestPath.HOLDER_REFERENCE).getValue(), StandardCharsets.UTF_8); } catch (NullPointerException e) { @@ -319,6 +293,11 @@ public String getAuthorityReferenceString() throws IOException public String getOuterAuthorityReferenceString() throws IOException { + if (CertificateRequestPath.CV_CERTIFICATE.getTag().equals(getDTag())) + { + return null; + } + try { return new String(this.getRequestPart(CertificateRequestPath.OUTER_CA_REFERENCE).getValue(), diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CvcRequestGenerator.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CvcRequestGenerator.java index b48a00ca..7e414736 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CvcRequestGenerator.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/certrequest/CvcRequestGenerator.java @@ -20,7 +20,7 @@ import java.security.interfaces.ECPublicKey; import java.util.Arrays; -import javax.annotation.Nullable; +import jakarta.annotation.Nullable; import de.governikus.eumw.poseidas.cardbase.AssertUtil; import de.governikus.eumw.poseidas.cardbase.asn1.ASN1; @@ -343,7 +343,6 @@ private static CertificateRequest createCleanRequest(ECCVCertificate rootCert) t { asn1.getChildElementByPath(ECCVCPath.CV_CERTIFICATE_BODY) .removeChildElement(asn1.getChildElementByPath(ECCVCPath.CA_REFERENCE), asn1); - asn1.getChildElementByPath(ECCVCPath.CV_CERTIFICATE_BODY) .removeChildElement(asn1.getChildElementByPath(ECCVCPath.EFFECTIVE_DATE), asn1); asn1.getChildElementByPath(ECCVCPath.CV_CERTIFICATE_BODY) diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/eac/protocol/EACServer.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/eac/protocol/EACServer.java index 771f9342..77175870 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/eac/protocol/EACServer.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/cardserver/eac/protocol/EACServer.java @@ -149,8 +149,8 @@ public EACServer() private EAC2InputTypeWrapper produceSecondInput(EAC1OutputTypeWrapper firstOutput, Object[] additionalParameters) throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, - InvalidKeyException, InvalidKeySpecException, SignatureException, UnrecoverableKeyException, - KeyStoreException, CertificateException, HSMException + InvalidKeyException, InvalidKeySpecException, SignatureException, UnrecoverableKeyException, KeyStoreException, + CertificateException, HSMException, InvalidEidException { AssertUtil.notNull(firstOutput, "first output"); AssertUtil.notNullOrEmpty(additionalParameters, "additional parameters"); @@ -160,11 +160,11 @@ private EAC2InputTypeWrapper produceSecondInput(EAC1OutputTypeWrapper firstOutpu } AssertUtil.notNull(additionalParameters[0], "instance of EAC1InputType"); AssertUtil.notNull(additionalParameters[1], "instance of CertAndKeyProvider"); - if (!EAC1InputTypeWrapper.class.isInstance(additionalParameters[0])) + if (!(additionalParameters[0] instanceof EAC1InputTypeWrapper)) { throw new IllegalArgumentException("parameter is not instance of EAC1InputType"); } - if (!CertAndKeyProvider.class.isInstance(additionalParameters[1])) + if (!(additionalParameters[1] instanceof CertAndKeyProvider)) { throw new IllegalArgumentException("parameter is not instance of CertAndKeyProvider"); } @@ -187,6 +187,10 @@ private EAC2InputTypeWrapper produceSecondInput(EAC1OutputTypeWrapper firstOutpu AssertUtil.notNullOrEmpty(paceInfoList, "list of PACE info"); this.caData = InfoSelector.selectCAData(caInfoList, caDomParamList); + if (this.caData == null) + { + throw new InvalidEidException("no acceptable chip authentication domain parameters found"); + } this.paceInfo = InfoSelector.selectPACEInfo(paceInfoList); OID protocol = this.caData.getCaDomParamInfo().getProtocol(); @@ -330,7 +334,7 @@ private EACFinal processCompleteTACAOutput(EAC2OutputTypeWrapper secondOutput, throw new IllegalArgumentException("exactly one parameter required as instance of SignedDataChecker"); } AssertUtil.notNull(additionalParameters[0], "instance of SignedDataChecker"); - if (!SignedDataChecker.class.isInstance(additionalParameters[0])) + if (!(additionalParameters[0] instanceof SignedDataChecker)) { throw new IllegalArgumentException("parameter is not instance of SignedDataChecker"); } @@ -449,7 +453,7 @@ public

P executeStep(int return parameterClass.cast(this.produceSecondInput((EAC1OutputTypeWrapper)result, additionalParameters)); } - catch (IllegalArgumentException e) + catch (IllegalArgumentException | InvalidEidException e) { throw e; } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/CVCController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/CVCController.java index 46e27da1..3079c9a2 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/CVCController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/CVCController.java @@ -15,11 +15,15 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.List; +import java.util.Objects; + +import jakarta.validation.Valid; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; @@ -131,7 +135,7 @@ public String details(@RequestParam(ENTITYID) String entityID, } model.addAttribute("entity", serviceProviderDetails); model.addAttribute("entityID", entityID); - model.addAttribute("form", new CVCRequestModel()); + model.addAttribute("form", Objects.requireNonNullElseGet(model.getAttribute("form"), CVCRequestModel::new)); return "pages/details"; } @@ -165,8 +169,7 @@ public String check(@RequestParam(ENTITYID) String entityID, RedirectAttributes * This route performs the initial certificate request */ @PostMapping("/initialRequest") - public String initialRequest(@RequestParam(ENTITYID) String entityID, - @ModelAttribute CVCRequestModel form, + public String initialRequest(@RequestParam(ENTITYID) String entityID, @Valid @ModelAttribute CVCRequestModel form, BindingResult bindingResult, RedirectAttributes redirectAttributes) { ServiceProviderDetails serviceProviderDetails = getServiceProviderDetails(entityID); @@ -176,20 +179,21 @@ public String initialRequest(@RequestParam(ENTITYID) String entityID, "Initial request failed: " + ERROR_MESSAGE_NO_SP_PRESENT, entityID); } + if (bindingResult.hasErrors()) { - String result = data.requestFirstTerminalCertificate(entityID, - form.getCountryCode(), - form.getChrMnemonic(), - form.getSequenceNumber()) - .toString(); - if (CO_MSG_OK_OK.equals(result)) - { - redirectAttributes.addFlashAttribute(SUCCESS, "Initial request succeeded"); - } - else - { + redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.form", bindingResult); + redirectAttributes.addFlashAttribute("form", form); + redirectAttributes.addFlashAttribute(ERROR, "Initial request was not sent. Please check \"Initial CVC request\" below."); + + } else { - redirectAttributes.addFlashAttribute(ERROR, "Initial request failed: " + result); + String result = data.requestFirstTerminalCertificate(entityID, form.getCountryCode(), form.getChrMnemonic(), form.getSequenceNumber()).toString(); + if (CO_MSG_OK_OK.equals(result)) { + redirectAttributes.addFlashAttribute(SUCCESS, "Initial request succeeded"); + } else { + + redirectAttributes.addFlashAttribute(ERROR, "Initial request failed: " + result); + } } redirectAttributes.addFlashAttribute(JUMP_TO_TAB, CVC); redirectAttributes.addAttribute(ENTITYID, entityID); diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/DvcaController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/DvcaController.java index 2fc17fb1..433a090e 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/DvcaController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/DvcaController.java @@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; -import javax.validation.Valid; +import jakarta.validation.Valid; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidController.java index 4e2bb6e8..92c2b39b 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidController.java @@ -5,7 +5,7 @@ import java.util.Set; import java.util.stream.Collectors; -import javax.validation.Valid; +import jakarta.validation.Valid; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidasController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidasController.java index ab8c0ca2..c9f3ee9a 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidasController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/EidasController.java @@ -1,13 +1,18 @@ package de.governikus.eumw.poseidas.config; +import java.security.KeyStore; +import java.security.cert.X509Certificate; import java.util.List; +import java.util.Optional; -import javax.validation.Valid; +import jakarta.validation.Valid; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; @@ -19,14 +24,21 @@ import de.governikus.eumw.config.EidasMiddlewareConfig; import de.governikus.eumw.config.OrganizationType; import de.governikus.eumw.eidascommon.ContextPaths; +import de.governikus.eumw.eidascommon.ErrorCodeException; +import de.governikus.eumw.eidascommon.Utils; +import de.governikus.eumw.eidasstarterkit.EidasSigner; import de.governikus.eumw.poseidas.config.model.forms.EidasConfigModel; +import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationException; import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; +import de.governikus.eumw.poseidas.server.pki.HSMServiceHolder; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Controller @RequestMapping(ContextPaths.ADMIN_CONTEXT_PATH + ContextPaths.EIDAS_CONFIG) @RequiredArgsConstructor +@Slf4j public class EidasController { @@ -37,6 +49,8 @@ public class EidasController private final ConfigurationService configurationService; + private final HSMServiceHolder hsmServiceHolder; + @Value("#{'${hsm.type:}' == 'PKCS11'}") private boolean isHsmInUse; @@ -52,13 +66,53 @@ public String index(Model model, @ModelAttribute String error, @ModelAttribute S model.addAttribute("msg", msg); } - model.addAttribute("eidasConfigModel", - toConfigModel(configurationService.getConfiguration() - .map(EidasMiddlewareConfig::getServerUrl) - .orElse(""), - configurationService.getConfiguration() - .map(EidasMiddlewareConfig::getEidasConfiguration) - .orElse(new EidasMiddlewareConfig.EidasConfiguration()))); + EidasConfigModel configModel = toConfigModel(configurationService.getConfiguration() + .map(EidasMiddlewareConfig::getServerUrl) + .orElse(""), + configurationService.getConfiguration() + .map(EidasMiddlewareConfig::getEidasConfiguration) + .orElse(new EidasMiddlewareConfig.EidasConfiguration())); + model.addAttribute("eidasConfigModel", configModel); + + KeyStore hsmKeyStore = hsmServiceHolder.getKeyStore(); + if (hsmKeyStore != null) + { + X509Certificate certificate = null; + try + { + certificate = (X509Certificate)hsmKeyStore.getCertificate(EidasSigner.SAML_SIGNING); + } + catch (Exception e) + { + log.warn("Cannot get the signature certificate of the middleware from the HSM", e); + String errorMessage = error + "Cannot get the signature certificate of the middleware from the HSM: " + + e.getMessage(); + model.addAttribute("error", errorMessage); + } + if (certificate != null) + { + try + { + Utils.ensureKeySize(certificate); + } + catch (ErrorCodeException e) + { + // Already logged in Utils, only the message of the UI is necessary + String errorMessage = "The signature certificate in the HSM does not meet the crypto requirements: " + + e.getMessage(); + model.addAttribute("error", errorMessage); + } + } + } + else if (StringUtils.isNotBlank(configModel.getSignatureKeyPairName())) + { + Optional optionalErrorMessage = checkSignatureCert(configModel.getSignatureKeyPairName()); + if (optionalErrorMessage.isPresent()) + { + String errorMessage = error + optionalErrorMessage.get(); + model.addAttribute("error", errorMessage); + } + } return INDEX_TEMPLATE; } @@ -81,6 +135,16 @@ public String save(@Valid @ModelAttribute EidasConfigModel configModel, return INDEX_TEMPLATE; } + if (StringUtils.isNotBlank(configModel.getSignatureKeyPairName())) + { + Optional optionalErrorMessage = checkSignatureCert(configModel.getSignatureKeyPairName()); + if (optionalErrorMessage.isPresent()) + { + bindingResult.addError(new FieldError("eidasConfigModel", "signatureKeyPairName", optionalErrorMessage.get())); + return INDEX_TEMPLATE; + } + } + final EidasMiddlewareConfig eidasMiddlewareConfig = configurationService.getConfiguration() .orElse(new EidasMiddlewareConfig()); eidasMiddlewareConfig.setEidasConfiguration(toConfigType(configModel)); @@ -92,6 +156,20 @@ public String save(@Valid @ModelAttribute EidasConfigModel configModel, return REDIRECT_TO_INDEX; } + private Optional checkSignatureCert(String signatureKeyPairName) + { + try + { + configurationService.getSamlKeyPair(signatureKeyPairName); + } + catch (ConfigurationException e) + { + log.warn("The signature certificate does not meet the crypto requirements", e); + return Optional.of("The signature certificate does not meet the crypto requirements: " + e.getMessage()); + } + return Optional.empty(); + } + private EidasConfigModel toConfigModel(String serverUrl, EidasMiddlewareConfig.EidasConfiguration config) { @@ -131,7 +209,8 @@ private EidasMiddlewareConfig.EidasConfiguration toConfigType(EidasConfigModel m model.getOrganizationLanguage(), model.getOrganizationUrl()), model.getPublicServiceProviderName(), null, - model.getSignatureKeyPairName(), + StringUtils.isBlank(model.getSignatureKeyPairName()) ? null + : model.getSignatureKeyPairName(), configurationService.getConfiguration() .map(EidasMiddlewareConfig::getEidasConfiguration) .map(EidasMiddlewareConfig.EidasConfiguration::getMetadataSignatureVerificationCertificateName) diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationController.java index fd8b2af5..9847f1fe 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationController.java @@ -11,7 +11,7 @@ import java.util.Set; import java.util.stream.Collectors; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/KeymanagementController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/KeymanagementController.java index 0917d485..11c8a5eb 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/KeymanagementController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/KeymanagementController.java @@ -24,7 +24,7 @@ import java.util.Set; import java.util.stream.Collectors; -import javax.validation.Valid; +import jakarta.validation.Valid; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Controller; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/MetadataController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/MetadataController.java index 186cde0f..7996dc63 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/MetadataController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/MetadataController.java @@ -6,13 +6,16 @@ import java.net.URISyntaxException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; -import javax.validation.Valid; +import jakarta.validation.Valid; +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -29,9 +32,11 @@ import de.governikus.eumw.config.ConnectorMetadataType; import de.governikus.eumw.config.EidasMiddlewareConfig; import de.governikus.eumw.eidascommon.ContextPaths; +import de.governikus.eumw.eidascommon.CryptoAlgUtil; import de.governikus.eumw.eidasstarterkit.EidasMetadataNode; import de.governikus.eumw.eidasstarterkit.EidasSaml; import de.governikus.eumw.poseidas.config.model.MetadataVerificationCertificateModel; +import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationException; import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; import de.governikus.eumw.poseidas.service.MetadataService; import lombok.RequiredArgsConstructor; @@ -63,7 +68,7 @@ public class MetadataController /** * Prepare index page. - * + * * @param model * @param error * @param msg @@ -76,52 +81,131 @@ public String index(Model model, @ModelAttribute String error, @ModelAttribute S { model.addAttribute(REDIRECT_ATTRIBUTE_ERROR, error); } - if (msg != null && !msg.isBlank()) + + List metadataFiles = getMetadataFiles(); + model.addAttribute("metafiles", metadataFiles); + List errorMessages = metadataFiles.stream() + .map(EidasMetadataEntry::errorMessage) + .filter(Objects::nonNull) + .toList(); + String appendCurrentMetadataErrorMessage = addInvalidMetadataErrorMessage(errorMessages, error); + if (!appendCurrentMetadataErrorMessage.isBlank()) { - model.addAttribute("msg", msg); + model.addAttribute(REDIRECT_ATTRIBUTE_ERROR, appendCurrentMetadataErrorMessage); + } + String metadataSignatureVerificationCertificateName = configurationService.getConfiguration() + .map(EidasMiddlewareConfig::getEidasConfiguration) + .map(EidasMiddlewareConfig.EidasConfiguration::getMetadataSignatureVerificationCertificateName) + .orElse(null); + if (StringUtils.isNotBlank(metadataSignatureVerificationCertificateName)) + { + // Ensure Key Size + try + { + configurationService.getSamlCertificate(metadataSignatureVerificationCertificateName); + } + catch (ConfigurationException e) + { + String errorMessage = error + "The currently selected metadata verification certificate is not valid: " + + e.getMessage(); + model.addAttribute(REDIRECT_ATTRIBUTE_ERROR, errorMessage); + } } - - model.addAttribute("metafiles", getMetadataFiles()); model.addAttribute("metadataVerificationModel", - new MetadataVerificationCertificateModel(configurationService.getConfiguration() - .map(EidasMiddlewareConfig::getEidasConfiguration) - .map(EidasMiddlewareConfig.EidasConfiguration::getMetadataSignatureVerificationCertificateName) - .orElse(null))); + new MetadataVerificationCertificateModel(metadataSignatureVerificationCertificateName)); return INDEX_TEMPLATE; } - private List getMetadataFiles() + private String addInvalidMetadataErrorMessage(List errorMessages, String error) + { + StringBuilder stringBuilder = new StringBuilder(error); + errorMessages.forEach(s -> stringBuilder.append('\n').append(s)); + return stringBuilder.toString(); + } + + private List getMetadataFiles() { return configurationService.getConfiguration() .map(EidasMiddlewareConfig::getEidasConfiguration) .map(EidasMiddlewareConfig.EidasConfiguration::getConnectorMetadata) .stream() .flatMap(List::stream) - .map(ConnectorMetadataType::getValue) - .map(this::parseToEidasMetadata) - .filter(Optional::isPresent) - .map(Optional::get) - .sorted(Comparator.comparing(EidasMetadataNode::getEntityId)) - .collect(Collectors.toList()); + .map(connectorMetadataType -> { + try + { + EidasMetadataNode eidasMetadataNode = parseToEidasMetadata(connectorMetadataType.getValue()); + return new EidasMetadataEntry(eidasMetadataNode.getEntityId(), + eidasMetadataNode.getCheckedAsValid(), null); + } + catch (Exception e) + { + log.warn("Cannot parse already saved metadata with entityId {}. This metadata is not usable by the middleware and must be deleted or replaced.", + connectorMetadataType.getEntityID(), + e); + String errorMessage = String.format("Cannot parse already saved metadata with entityId %s. This metadata is not usable by the middleware and must be deleted or replaced. See the log of the middleware for more details.", + connectorMetadataType.getEntityID()); + return new EidasMetadataEntry(connectorMetadataType.getEntityID(), Boolean.FALSE, + errorMessage); + } + }) + .sorted(Comparator.comparing(EidasMetadataEntry::entityId)) + .toList(); + } + + record EidasMetadataEntry(String entityId, Boolean checkedAsValid, String errorMessage) { } - private Optional parseToEidasMetadata(byte[] bytes) + private EidasMetadataNode parseToEidasMetadata(byte[] bytes) throws Exception { - final Optional optionalMetadataVerificationCertificate = configurationService.getConfiguration() - .map(EidasMiddlewareConfig::getEidasConfiguration) - .map(EidasMiddlewareConfig.EidasConfiguration::getMetadataSignatureVerificationCertificateName); + final Optional metadataVerificationCertificateName = configurationService.getConfiguration() + .map(EidasMiddlewareConfig::getEidasConfiguration) + .map(EidasMiddlewareConfig.EidasConfiguration::getMetadataSignatureVerificationCertificateName); + + EntityDescriptor metadata; + try + { + metadata = EidasSaml.unmarshalMetadata(new ByteArrayInputStream(bytes)); + } + catch (Exception e) + { + log.info("Could not parse metadata!", e); + throw e; + } + + if (metadata.isSigned()) + { + try + { + CryptoAlgUtil.verifyDigestAndSignatureAlgorithm(metadata.getSignature()); + } + catch (Exception e) + { + log.info("Invalid digest hash algorithm or signature algorithm used for the signature of the metadata", e); + throw e; + } + } + + X509Certificate signatureVerificationCertificate = null; + if (metadataVerificationCertificateName.isPresent()) + { + try + { + signatureVerificationCertificate = configurationService.getSamlCertificate(metadataVerificationCertificateName.get()); + } + catch (ConfigurationException e) + { + log.warn("Cannot get or use the metadata verification certificate", e); + } + } + try { - return Optional.of(EidasSaml.parseMetaDataNode(new ByteArrayInputStream(bytes), - optionalMetadataVerificationCertificate.isPresent() - ? configurationService.getCertificate(optionalMetadataVerificationCertificate.get()) - : null, - true)); + return EidasSaml.parseMetaDataNode(new ByteArrayInputStream(bytes), signatureVerificationCertificate, true); } catch (Exception e) { log.info("Could not parse metadata!", e); - return Optional.empty(); + throw e; } } @@ -139,7 +223,7 @@ private Optional getMetadataFileAsBytes(String entityID) /** * Remove a metadata file from config (first step, will ask for confirmation). - * + * * @param model * @param entityIDUrlEncoded URL encoded entityID of the metadata to be deleted * @param redirectAttributes @@ -164,7 +248,7 @@ public String remove(Model model, /** * Remove a metadata file from config (second step, call when confirmation has been given). - * + * * @param entityIDUrlEncoded URL encoded entityID of the metadata to be deleted * @param redirectAttributes * @return redirect @@ -195,7 +279,7 @@ public String removeConfirmed(@RequestParam(name = "entityID") String entityIDUr /** * Download a metadata file. - * + * * @param entityIDUrlEncoded URL encoded entityID of the metadata to be downloaded * @param redirectAttributes * @return @@ -220,7 +304,7 @@ public Object downloadConnectorMetadata(@RequestParam(name = "entityID") String /** * Download the metadata of the middleware. - * + * * @param redirectAttributes * @param referer * @return @@ -254,7 +338,7 @@ public Object downloadMiddlewareMetadata(RedirectAttributes redirectAttributes, /** * Upload metadata file. - * + * * @param metadataFile * @param redirectAttributes * @return @@ -271,25 +355,16 @@ public String uploadMetadata(@RequestParam("metadataFile") MultipartFile metadat try { // Check if metadata can be parsed! - final Optional optionalEidasMetadataNode = parseToEidasMetadata(metadataFile.getBytes()); - if (optionalEidasMetadataNode.isEmpty()) + final EidasMetadataNode eidasMetadataNode = parseToEidasMetadata(metadataFile.getBytes()); + final String entityId = eidasMetadataNode.getEntityId(); + if (getMetadataFileAsBytes(entityId).isPresent()) { redirectAttributes.addFlashAttribute(REDIRECT_ATTRIBUTE_ERROR, - "Metadata file is not valid and could not be parsed!"); + "There is a metadata file already uploaded with the entityID " + entityId + + " !"); return REDIRECT_TO_INDEX; } - else - { - final String entityId = optionalEidasMetadataNode.get().getEntityId(); - if (getMetadataFileAsBytes(entityId).isPresent()) - { - redirectAttributes.addFlashAttribute(REDIRECT_ATTRIBUTE_ERROR, - "There is a metadata file already uploaded with the entityID " + entityId - + " !"); - return REDIRECT_TO_INDEX; - } - eidasConfiguration.getConnectorMetadata().add(new ConnectorMetadataType(metadataFile.getBytes(), entityId)); - } + eidasConfiguration.getConnectorMetadata().add(new ConnectorMetadataType(metadataFile.getBytes(), entityId)); } catch (IOException e) { @@ -297,6 +372,12 @@ public String uploadMetadata(@RequestParam("metadataFile") MultipartFile metadat redirectAttributes.addFlashAttribute("msg", "Could not upload file!"); return REDIRECT_TO_INDEX; } + catch (Exception e) + { + log.warn("Could not save metadata file", e); + redirectAttributes.addFlashAttribute("msg", e.getMessage()); + return REDIRECT_TO_INDEX; + } eidasMiddlewareConfig.setEidasConfiguration(eidasConfiguration); configurationService.saveConfiguration(eidasMiddlewareConfig, false); @@ -307,7 +388,7 @@ public String uploadMetadata(@RequestParam("metadataFile") MultipartFile metadat /** * Upload metadata verification certificate. - * + * * @param metadataVerificationCertificateModel * @param redirectAttributes * @return @@ -316,6 +397,20 @@ public String uploadMetadata(@RequestParam("metadataFile") MultipartFile metadat public String uploadMetadataVerificationCertificate(@Valid @ModelAttribute MetadataVerificationCertificateModel metadataVerificationCertificateModel, RedirectAttributes redirectAttributes) { + // Verify the key size of the verification certificate + try + { + configurationService.getSamlCertificate(metadataVerificationCertificateModel.getMetadataSignatureVerificationCertificateName()); + } + catch (ConfigurationException e) + { + // Exception message already logged in Utils.ensureKeySize + redirectAttributes.addFlashAttribute(REDIRECT_ATTRIBUTE_ERROR, + "Cannot save the selected metadata verification certificate: " + + e.getMessage()); + return REDIRECT_TO_INDEX; + } + final EidasMiddlewareConfig eidasMiddlewareConfig = configurationService.getConfiguration() .orElseGet(EidasMiddlewareConfig::new); diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/OverviewController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/OverviewController.java index 0816a8ca..f3c0845e 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/OverviewController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/OverviewController.java @@ -14,7 +14,7 @@ import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ServiceProviderController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ServiceProviderController.java index 738a7e34..36644d48 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ServiceProviderController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/ServiceProviderController.java @@ -13,7 +13,7 @@ import java.util.Optional; import java.util.stream.Collectors; -import javax.validation.Valid; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; @@ -472,5 +472,4 @@ private KeypairInfoHolder keyPairTypeToInfoHolder(KeyPairType keyPairType) throw new CertificateException("Could not work with certificate of keypair: " + keyPairType.getName(), e); } } - } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/TimerController.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/TimerController.java index 24e3af55..f425f737 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/TimerController.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/TimerController.java @@ -2,7 +2,7 @@ import java.util.Optional; -import javax.validation.Valid; +import jakarta.validation.Valid; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CertificateUploadModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CertificateUploadModel.java index 30e43bb8..157ed3d7 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CertificateUploadModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CertificateUploadModel.java @@ -1,6 +1,6 @@ package de.governikus.eumw.poseidas.config.model; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateCertificateFromKeystoreModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateCertificateFromKeystoreModel.java index 37ef7e20..4c43c830 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateCertificateFromKeystoreModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateCertificateFromKeystoreModel.java @@ -1,7 +1,7 @@ package de.governikus.eumw.poseidas.config.model; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateKeypairFromKeystoreModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateKeypairFromKeystoreModel.java index 5d8f42b6..10e3f7dc 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateKeypairFromKeystoreModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/CreateKeypairFromKeystoreModel.java @@ -1,7 +1,7 @@ package de.governikus.eumw.poseidas.config.model; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/KeystoreUploadModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/KeystoreUploadModel.java index c702d26b..7927af8a 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/KeystoreUploadModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/KeystoreUploadModel.java @@ -1,7 +1,7 @@ package de.governikus.eumw.poseidas.config.model; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/MetadataVerificationCertificateModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/MetadataVerificationCertificateModel.java index 955def03..09677923 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/MetadataVerificationCertificateModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/MetadataVerificationCertificateModel.java @@ -9,7 +9,7 @@ package de.governikus.eumw.poseidas.config.model; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotEmpty; import de.governikus.eumw.poseidas.config.validation.CertificateNameExists; import lombok.AllArgsConstructor; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/ServiceProviderDetails.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/ServiceProviderDetails.java index 5127fbe4..6d07ce34 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/ServiceProviderDetails.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/ServiceProviderDetails.java @@ -9,9 +9,6 @@ package de.governikus.eumw.poseidas.config.model; -import static de.governikus.eumw.poseidas.cardserver.certrequest.CvcRequestGenerator.increaseCHR; -import static de.governikus.eumw.poseidas.server.pki.CVCRequestHandler.getHolderReferenceStringOfPendingRequest; - import java.io.IOException; import java.text.SimpleDateFormat; import java.time.Instant; @@ -23,7 +20,9 @@ import de.governikus.eumw.config.ServiceProviderType; import de.governikus.eumw.poseidas.cardbase.asn1.npa.ECCVCertificate; +import de.governikus.eumw.poseidas.cardserver.certrequest.CvcRequestGenerator; import de.governikus.eumw.poseidas.gov2server.constants.admin.AdminPoseidasConstants; +import de.governikus.eumw.poseidas.server.pki.CVCRequestHandler; import de.governikus.eumw.poseidas.server.pki.PendingCertificateRequest; import de.governikus.eumw.poseidas.server.pki.TerminalPermission; import de.governikus.eumw.poseidas.server.pki.TerminalPermissionAOBean; @@ -271,7 +270,7 @@ public Integer getSuggestedCvcNextSequence() throws IOException PendingCertificateRequest pendingRequest = terminalPermission.getPendingRequest(); if (pendingRequest != null) { - String currentHolderReference = getHolderReferenceStringOfPendingRequest(pendingRequest); + String currentHolderReference = CVCRequestHandler.getHolderReferenceStringOfPendingRequest(pendingRequest); if (currentHolderReference != null) { // If pending may be reused, suggest sequence number of pending request @@ -292,7 +291,7 @@ public Integer getSuggestedCvcNextSequence() throws IOException getCVCRefID()); } // If pending may not be reused, suggest increased sequence number - return getNumberOfCHR(increaseCHR(currentHolderReference)); + return getNumberOfCHR(CvcRequestGenerator.increaseCHR(currentHolderReference)); } } @@ -316,7 +315,7 @@ public Integer getSuggestedCvcNextSequence() throws IOException } // If no last sequence or pending request but cvc is available, suggest increased cvc sequence number - return getNumberOfCHR(increaseCHR(new ECCVCertificate(terminalPermission.getCvc()).getHolderReferenceString())); + return getNumberOfCHR(CvcRequestGenerator.increaseCHR(new ECCVCertificate(terminalPermission.getCvc()).getHolderReferenceString())); } public static Integer getNumberOfCHR(String currentHolderReference) diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/CVCRequestModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/CVCRequestModel.java index 196fd027..cbf53cd8 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/CVCRequestModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/CVCRequestModel.java @@ -9,6 +9,12 @@ package de.governikus.eumw.poseidas.config.model.forms; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.Length; +import org.hibernate.validator.constraints.Range; + import lombok.Data; @@ -21,11 +27,17 @@ public class CVCRequestModel { + @NotBlank(message = "Country code must not be empty") + @Length(min = 2, max = 2, message = "Country code has to be exactly 2 characters long") private String countryCode; + @NotBlank(message = "CHR Mnemonic must not be empty") + @Length(max = 9, message = "CHR Mnemonic must not be longer than 9 characters") private String chrMnemonic; - private int sequenceNumber; + @Range(min = 0, max = 99999, message = "Sequence number must be between 0-99999") + @NotNull(message = "Sequence number must not be empty") + private Integer sequenceNumber; private String rscChr; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/DvcaConfigModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/DvcaConfigModel.java index 2acb3946..ac96397d 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/DvcaConfigModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/DvcaConfigModel.java @@ -1,6 +1,6 @@ package de.governikus.eumw.poseidas.config.model.forms; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; import org.hibernate.validator.constraints.URL; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidConfigModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidConfigModel.java index c3c126f5..cbe67091 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidConfigModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidConfigModel.java @@ -1,6 +1,6 @@ package de.governikus.eumw.poseidas.config.model.forms; -import javax.validation.constraints.Pattern; +import jakarta.validation.constraints.Pattern; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidasConfigModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidasConfigModel.java index 67ce5470..75084f2d 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidasConfigModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/EidasConfigModel.java @@ -1,7 +1,7 @@ package de.governikus.eumw.poseidas.config.model.forms; -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.URL; @@ -55,7 +55,6 @@ public class EidasConfigModel private String organizationUrl; @KeyPairNameExists - @NotEmpty(message = "Has to be selected") private String signatureKeyPairName; private boolean signMetadata; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/ServiceProviderConfigModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/ServiceProviderConfigModel.java index c88405aa..2179d9ab 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/ServiceProviderConfigModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/ServiceProviderConfigModel.java @@ -1,7 +1,8 @@ package de.governikus.eumw.poseidas.config.model.forms; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotBlank; + +import org.apache.commons.lang3.StringUtils; import de.governikus.eumw.config.ServiceProviderType; import de.governikus.eumw.poseidas.config.validation.DvcaConfigNameExists; @@ -24,7 +25,6 @@ public class ServiceProviderConfigModel private String dvcaConfigurationName; @KeyPairNameExists - @NotEmpty(message = "Has to be selected") private String clientKeyPairName; @NotBlank(message = "May not be empty") @@ -34,11 +34,13 @@ public class ServiceProviderConfigModel public ServiceProviderType toServiceProviderType() { - return new ServiceProviderType(name, enabled, name, dvcaConfigurationName, clientKeyPairName); + return new ServiceProviderType(name, enabled, name, dvcaConfigurationName, + StringUtils.isBlank(clientKeyPairName) ? null : clientKeyPairName); } public ServiceProviderType toServiceProviderType(String cvcRefID) { - return new ServiceProviderType(name, enabled, cvcRefID, dvcaConfigurationName, clientKeyPairName); + return new ServiceProviderType(name, enabled, cvcRefID, dvcaConfigurationName, + StringUtils.isBlank(clientKeyPairName) ? null : clientKeyPairName); } } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/TimerConfigModel.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/TimerConfigModel.java index 87152ffe..dc5297da 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/TimerConfigModel.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/model/forms/TimerConfigModel.java @@ -1,7 +1,7 @@ package de.governikus.eumw.poseidas.config.model.forms; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Positive; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; import de.governikus.eumw.config.TimerUnit; import lombok.AllArgsConstructor; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExists.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExists.java index aa23938a..b1bade31 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExists.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExists.java @@ -8,8 +8,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.Payload; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExistsValidator.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExistsValidator.java index 72630b41..50b33d98 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExistsValidator.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/CertificateNameExistsValidator.java @@ -1,7 +1,7 @@ package de.governikus.eumw.poseidas.config.validation; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExists.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExists.java index d05226df..09a6c976 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExists.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExists.java @@ -8,8 +8,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.Payload; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExistsValidator.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExistsValidator.java index b2048c6a..e20cea42 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExistsValidator.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/DvcaConfigNameExistsValidator.java @@ -2,8 +2,8 @@ import java.util.List; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import org.springframework.stereotype.Component; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExists.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExists.java index 678b7cc1..4a7538de 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExists.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExists.java @@ -8,8 +8,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.Payload; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExistsValidator.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExistsValidator.java index 406c6689..88317e3f 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExistsValidator.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/KeyPairNameExistsValidator.java @@ -1,7 +1,7 @@ package de.governikus.eumw.poseidas.config.validation; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExists.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExists.java index 26fc5217..b9e39fb7 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExists.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExists.java @@ -8,8 +8,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import javax.validation.Constraint; -import javax.validation.Payload; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExistsValidator.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExistsValidator.java index 9de822e5..45f1c053 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExistsValidator.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/config/validation/ServiceProviderNameExistsValidator.java @@ -2,8 +2,8 @@ import java.util.List; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; import org.springframework.stereotype.Component; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/ecardcore/utilities/ECardCoreUtil.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/ecardcore/utilities/ECardCoreUtil.java index db7d6da3..4774297b 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/ecardcore/utilities/ECardCoreUtil.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/ecardcore/utilities/ECardCoreUtil.java @@ -10,7 +10,7 @@ package de.governikus.eumw.poseidas.ecardcore.utilities; -import javax.xml.bind.JAXBElement; +import jakarta.xml.bind.JAXBElement; import oasis.names.tc.dss._1_0.core.schema.InternationalStringType; import oasis.names.tc.dss._1_0.core.schema.ObjectFactory; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/convenience/EIDSequence.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/convenience/EIDSequence.java index 7a6442d4..223343ad 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/convenience/EIDSequence.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/convenience/EIDSequence.java @@ -19,7 +19,7 @@ import java.util.List; import java.util.Set; -import javax.xml.bind.JAXBElement; +import jakarta.xml.bind.JAXBElement; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -776,8 +776,9 @@ private Object handleAuthenticationProtocolData(EAC1OutputTypeWrapper eac1Output } catch (InvalidEidException e) { - // should not be thrown in this step, if this ever is reached we do have a problem - return handleError(ResultMinor.COMMON_INTERNAL_ERROR, e.getMessage()); + LOG.debug(logPrefix + "Unsafe domain parameters detected...abort process"); + eidInfoContainer.setStatus(EIDStatus.NOT_AUTHENTIC); + throw new ECardException(ResultMinor.SAL_SECURITY_CONDITION_NOT_SATISFIED, e); } // If the cakProvider for some reason does not provide a certificate chain for the CVC diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataChecker.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataChecker.java index 15848ec1..a2f8f4e1 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataChecker.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataChecker.java @@ -24,6 +24,8 @@ import de.governikus.eumw.config.EidasMiddlewareConfig; import de.governikus.eumw.poseidas.SpringApplicationContextHelper; import de.governikus.eumw.poseidas.cardbase.asn1.ASN1; +import de.governikus.eumw.poseidas.cardbase.constants.OIDConstants; +import de.governikus.eumw.poseidas.cardbase.crypto.HashConstants; import de.governikus.eumw.poseidas.cardserver.eac.crypto.SignedDataChecker; import de.governikus.eumw.poseidas.eidserver.crl.CertificationRevocationListImpl; import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; @@ -54,7 +56,16 @@ public class EACSignedDataChecker extends EACSignedDataParser implements SignedD public EACSignedDataChecker(List masterList, String logPrefix) { super(logPrefix); - cmsSignatureChecker = new CmsSignatureChecker(masterList); + //The allowed Digest Algorithms and Signature Algorithms can be found in TR-3116-2 2.1.2 (Status 2023) + //The allowed elliptic curves can be found in TR-3116-2 1.4.2 (Status 2023) + cmsSignatureChecker = new CmsSignatureChecker(masterList, + Set.of(HashConstants.SHA256_OID_STRING, + HashConstants.SHA384_OID_STRING, + HashConstants.SHA512_OID_STRING), + Set.of(OIDConstants.OID_ECDSA_SHA256.getOIDString(), + OIDConstants.OID_ECDSA_SHA384.getOIDString(), + OIDConstants.OID_ECDSA_SHA512.getOIDString()), + Set.of("brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1")); this.allowedDocumentTypes = getAllowedDocuments(); } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataParser.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataParser.java index d1c8976b..8a025576 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataParser.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataParser.java @@ -55,7 +55,7 @@ SignedData getSignedData(byte[] data) throws IOException LOG.debug(logPrefix + "Unexpected size of signature data for ASN1: " + signatureObjectSize); } ASN1TaggedObject dto = (ASN1TaggedObject)(seq.getObjectAt(1)); - SignedData signedDataFromCard = new SignedData((ASN1Sequence)(dto.getObject())); + SignedData signedDataFromCard = new SignedData((ASN1Sequence)(dto.getBaseObject())); LOG.debug(logPrefix + "Check signature data:\n " + signedDataFromCard.getSignerInfos().toString()); return signedDataFromCard; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/model/signeddata/AbstractASN1List.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/model/signeddata/AbstractASN1List.java index 8b8ee253..3ada7f43 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/model/signeddata/AbstractASN1List.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/eidserver/model/signeddata/AbstractASN1List.java @@ -112,7 +112,7 @@ private void parseDERSequence(ASN1Sequence obj) throws IOException // Try to find the ObjectId for the list if (identifier.equals(identifierInList)) { - ASN1Primitive object = ((ASN1TaggedObject)parser.readObject()).getObject(); + ASN1Primitive object = ((ASN1TaggedObject)parser.readObject()).getBaseObject().toASN1Primitive(); parseList(object); catalogued = true; return; @@ -157,7 +157,7 @@ private void parseASN1Encodable(ASN1Encodable obj) throws IOException } else if (obj instanceof ASN1TaggedObject) { - parseASN1Encodable(((ASN1TaggedObject)obj).getObject()); + parseASN1Encodable(((ASN1TaggedObject)obj).getBaseObject()); } } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/PaosReceiver.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/PaosReceiver.java index d3975cee..fb2eccab 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/PaosReceiver.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/PaosReceiver.java @@ -12,10 +12,10 @@ import java.io.IOException; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/Util.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/Util.java index 8d88c639..fff92ab7 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/Util.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/authentication/paos/Util.java @@ -16,18 +16,18 @@ import java.util.UUID; import javax.xml.XMLConstants; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Unmarshaller; import javax.xml.catalog.CatalogFeatures; import javax.xml.catalog.CatalogManager; import javax.xml.catalog.CatalogResolver; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.soap.MessageFactory; -import javax.xml.soap.SOAPException; -import javax.xml.soap.SOAPHeader; -import javax.xml.soap.SOAPMessage; +import jakarta.xml.soap.MessageFactory; +import jakarta.xml.soap.SOAPException; +import jakarta.xml.soap.SOAPHeader; +import jakarta.xml.soap.SOAPMessage; import javax.xml.validation.SchemaFactory; import org.w3c.dom.Document; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/AbstractPaosHandler.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/AbstractPaosHandler.java index e7999bd5..3e91e8b6 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/AbstractPaosHandler.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/AbstractPaosHandler.java @@ -14,13 +14,13 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.bind.JAXBException; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.xml.bind.JAXBException; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.soap.SOAPException; -import javax.xml.soap.SOAPMessage; +import jakarta.xml.soap.SOAPException; +import jakarta.xml.soap.SOAPMessage; import javax.xml.transform.TransformerException; import org.apache.commons.logging.Log; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/DefaultPaosHandler.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/DefaultPaosHandler.java index 3b3f95a7..025ef319 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/DefaultPaosHandler.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/DefaultPaosHandler.java @@ -14,10 +14,10 @@ import java.io.IOException; import java.io.PrintWriter; -import javax.servlet.http.HttpServletRequest; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Marshaller; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/PaosHandlerFactory.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/PaosHandlerFactory.java index 73cd5c1a..e16fe3ce 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/PaosHandlerFactory.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/paosservlet/paos/handler/PaosHandlerFactory.java @@ -12,8 +12,8 @@ import java.io.IOException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/common/CSPFilter.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/common/CSPFilter.java index 88918a3c..bde9731b 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/common/CSPFilter.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/common/CSPFilter.java @@ -12,13 +12,13 @@ import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletResponse; public class CSPFilter implements Filter diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/Configuration.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/Configuration.java index 662b30ba..f7ddbe53 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/Configuration.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/Configuration.java @@ -2,10 +2,10 @@ import lombok.Data; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Lob; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationService.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationService.java index 2ddef7be..7e91dc5d 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationService.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationService.java @@ -32,6 +32,7 @@ import de.governikus.eumw.config.ServiceProviderType; import de.governikus.eumw.eidascommon.ContextPaths; import de.governikus.eumw.eidascommon.ErrorCodeException; +import de.governikus.eumw.eidascommon.Utils; import de.governikus.eumw.eidasmiddleware.eid.RequestingServiceProvider; import de.governikus.eumw.eidasstarterkit.EidasMetadataNode; import de.governikus.eumw.eidasstarterkit.EidasSaml; @@ -213,6 +214,40 @@ public KeyPair getKeyPair(String keyPairName) } } + public KeyPair getSamlKeyPair(String keyPairName) + { + KeyPair keyPair = getKeyPair(keyPairName); + try + { + Utils.ensureKeySize(keyPair.getCertificate()); + } + catch (ErrorCodeException e) + { + throw new ConfigurationException("The key pair does not fulfill the eIDAS crypto requirements: " + + e.getMessage()); + } + return keyPair; + } + + /** + * Get the certificate with the given name. Additionally, check that the certificate meets the crypto requirements for + * SAML certificates. + */ + public X509Certificate getSamlCertificate(String certificateName) + { + X509Certificate certificate = getCertificate(certificateName); + try + { + Utils.ensureKeySize(certificate); + } + catch (ErrorCodeException e) + { + throw new ConfigurationException("The certificate does not fulfill the eIDAS crypto requirements: " + + e.getMessage()); + } + return certificate; + } + /** * Get the certificate with the given name */ @@ -253,7 +288,7 @@ public RequestingServiceProvider getProviderByEntityID(String entityID) throw new ConfigurationException("No metadata verification certificate present in the configuration"); } - var metadataSignatureVerificationCertificate = getCertificate(metadataSignatureVerificationCertificateName); + var metadataSignatureVerificationCertificate = getSamlCertificate(metadataSignatureVerificationCertificateName); ConnectorMetadataType metadata = getConfiguration().orElseThrow(() -> new ConfigurationException("No configuration present")) .getEidasConfiguration() diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/CvcTlsCheck.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/CvcTlsCheck.java index b610d1aa..aac24805 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/CvcTlsCheck.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/config/CvcTlsCheck.java @@ -152,7 +152,7 @@ private CvcCheckResults getCvcResultsForSp(ServiceProviderType sp, } catch (IllegalArgumentException e) { - // happens if no cvc in terminalpermission + log.warn(e.getMessage()); } } return cvcResults; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/RequestIdStore.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/RequestIdStore.java index bbc9e6ba..4a0f7bbc 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/RequestIdStore.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/RequestIdStore.java @@ -12,8 +12,8 @@ import java.util.Objects; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStore.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStore.java index 3fddb8fc..da521d63 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStore.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStore.java @@ -12,10 +12,10 @@ import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Lob; -import javax.persistence.NamedQuery; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.NamedQuery; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStorePK.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStorePK.java index b1f735e6..0f85e8cb 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStorePK.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionInStorePK.java @@ -13,7 +13,7 @@ import java.io.Serializable; import java.util.Objects; -import javax.persistence.Embeddable; +import jakarta.persistence.Embeddable; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionStoreAOBean.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionStoreAOBean.java index e6485979..e60eadf0 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionStoreAOBean.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/idprovider/core/SessionStoreAOBean.java @@ -13,10 +13,10 @@ import java.util.Collection; import java.util.HashSet; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.TypedQuery; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.TypedQuery; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgent.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgent.java index 15a34b16..9ee80038 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgent.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgent.java @@ -20,7 +20,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.snmp4j.CommandResponder; import org.snmp4j.CommandResponderEvent; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPTrapSender.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPTrapSender.java index 6edd11ba..258d4f1c 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPTrapSender.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/monitoring/SNMPTrapSender.java @@ -12,8 +12,8 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; import org.snmp4j.PDU; import org.snmp4j.SNMP4JSettings; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntry.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntry.java index f1fee0fd..99e92ae5 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntry.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntry.java @@ -12,9 +12,9 @@ import java.io.Serializable; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQuery; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQuery; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntryPK.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntryPK.java index cf6c6bdf..30dc8c53 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntryPK.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/BlackListEntryPK.java @@ -13,7 +13,7 @@ import java.io.Serializable; import java.util.Objects; -import javax.persistence.Embeddable; +import jakarta.persistence.Embeddable; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCRequestHandler.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCRequestHandler.java index b91bdfb1..a596589e 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCRequestHandler.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCRequestHandler.java @@ -29,13 +29,14 @@ import java.util.Map; import java.util.Set; -import javax.xml.bind.DatatypeConverter; -import javax.xml.ws.WebServiceException; +import jakarta.xml.bind.DatatypeConverter; +import jakarta.xml.ws.WebServiceException; -import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang3.ArrayUtils; import de.governikus.eumw.config.ServiceProviderType; import de.governikus.eumw.eidascommon.Utils; +import de.governikus.eumw.poseidas.cardbase.ByteUtil; import de.governikus.eumw.poseidas.cardbase.Hex; import de.governikus.eumw.poseidas.cardbase.asn1.ASN1; import de.governikus.eumw.poseidas.cardbase.asn1.npa.CertificateDescription; @@ -43,7 +44,6 @@ import de.governikus.eumw.poseidas.cardbase.asn1.npa.ECCVCertificate; import de.governikus.eumw.poseidas.cardbase.asn1.npa.ECPublicKeyPath; import de.governikus.eumw.poseidas.cardserver.certrequest.CertificateRequest; -import de.governikus.eumw.poseidas.cardserver.certrequest.CertificateRequestPath; import de.governikus.eumw.poseidas.cardserver.certrequest.CvcRequestGenerator.CvcRequestData; import de.governikus.eumw.poseidas.eidmodel.TerminalData; import de.governikus.eumw.poseidas.eidserver.crl.CertificationRevocationListImpl; @@ -127,7 +127,7 @@ private static void checkCVC(byte[] newCvcBytes, byte[] oldCvcBytes, byte[][] chain, ASN1 publicKey, - ASN1 holderReference, + String holderReference, Date actualDate, String cvcRefId) throws CertificateException, GovManagementException @@ -259,21 +259,16 @@ private static void checkCVC(byte[] newCvcBytes, */ private static byte[] getBasicHolderReference(TerminalData newCVC) { - byte[] newHolderReference = new byte[newCVC.getHolderReference().length - 5]; - System.arraycopy(newCVC.getHolderReference(), 0, newHolderReference, 0, newHolderReference.length); - return newHolderReference; + return ByteUtil.subbytes(newCVC.getHolderReference(), 0, newCVC.getHolderReference().length - 5); } /** * @param holderReference * @return */ - private static byte[] getBasicHolderReference(ASN1 holderReference) + private static byte[] getBasicHolderReference(String holderReference) { - byte[] hrBytes = holderReference.getValue(); - byte[] newHolderReference = new byte[hrBytes.length - 5]; - System.arraycopy(hrBytes, 0, newHolderReference, 0, newHolderReference.length); - return newHolderReference; + return holderReference.substring(0, holderReference.length() - 5).getBytes(); } /** @@ -594,26 +589,20 @@ private ManagementMessage renewCvc(TerminalPermission tp, boolean usePendingRsc) public static String getHolderReferenceStringOfPendingRequest(PendingCertificateRequest pendingCertificateRequest) { + if (pendingCertificateRequest == null) + { + return null; + } + // Get encoded certificate request + byte[] requestData = pendingCertificateRequest.getRequestData(); + if (ArrayUtils.isEmpty(requestData)) + { + return null; + } + try { - if (pendingCertificateRequest == null) - { - return null; - } - // Get encoded certificate request - byte[] requestData = pendingCertificateRequest.getRequestData(); - if (ArrayUtils.isEmpty(requestData)) - { - return null; - } - // Encoded certificate request is wrapped in an application tag, that needs to be unwrapped (removed) for parsing - ASN1 asn1 = new ASN1(requestData); - byte[] value = asn1.getValue(); - if (value == null) - { - return null; - } - CertificateRequest certificateRequest = new CertificateRequest(value); + CertificateRequest certificateRequest = new CertificateRequest(new ByteArrayInputStream(requestData)); return certificateRequest.getHolderReferenceString(); } catch (IOException e) @@ -715,17 +704,9 @@ private void installNewCertificate(byte[] cert) throws GovManagementException chainForCheck[cin.getKey().getPosInChain()] = cin.getData(); } } - byte[] requestData = pendingCertificateRequest.getRequestData(); - CertificateRequest certificateRequest = new CertificateRequest(new ByteArrayInputStream(requestData), true); - ASN1 publicKey = certificateRequest.getChildElementByPath(CertificateRequestPath.PUBLIC_KEY); - if (publicKey == null) - { - ASN1[] bodies = certificateRequest.getChildElementsByTag(CertificateRequestPath.CV_CERTIFICATE_BODY.getTag()); - ASN1 body = bodies[0]; - ASN1[] publicKeys = body.getChildElementsByTag(CertificateRequestPath.PUBLIC_KEY.getTag()); - publicKey = publicKeys[0]; - } - ASN1 holderReference = certificateRequest.getChildElementByPath(CertificateRequestPath.HOLDER_REFERENCE); + CertificateRequest certificateRequest = new CertificateRequest(new ByteArrayInputStream(pendingCertificateRequest.getRequestData())); + ASN1 publicKey = certificateRequest.getPublicKey(); + String holderReference = certificateRequest.getHolderReferenceString(); checkCVC(cert, tp.getCvc(), chainForCheck, publicKey, holderReference, new Date(), cvcRefId); } catch (Exception e) diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCUpdateLock.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCUpdateLock.java index b234bbd0..bd0fe271 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCUpdateLock.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CVCUpdateLock.java @@ -12,8 +12,8 @@ import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChain.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChain.java index 014b849e..2e251903 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChain.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChain.java @@ -12,11 +12,11 @@ import java.io.Serializable; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.Lob; -import javax.persistence.ManyToOne; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChainPK.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChainPK.java index cc6ba9c2..9046e348 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChainPK.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CertInChainPK.java @@ -13,7 +13,7 @@ import java.io.Serializable; import java.util.Objects; -import javax.persistence.Embeddable; +import jakarta.persistence.Embeddable; import lombok.AccessLevel; import lombok.AllArgsConstructor; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ChangeKeyLock.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ChangeKeyLock.java index 00203eea..63419ce1 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ChangeKeyLock.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ChangeKeyLock.java @@ -12,9 +12,9 @@ import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQuery; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQuery; import de.governikus.eumw.poseidas.cardbase.AssertUtil; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CmsSignatureChecker.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CmsSignatureChecker.java index fa4274e4..0c8e3192 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CmsSignatureChecker.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/CmsSignatureChecker.java @@ -28,6 +28,7 @@ import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.CMSSignedData; @@ -38,6 +39,7 @@ import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.util.Store; +import de.governikus.eumw.poseidas.cardbase.ByteUtil; import de.governikus.eumw.poseidas.cardserver.CertificateUtil; import de.governikus.eumw.poseidas.eidserver.crl.CertificationRevocationListImpl; import de.governikus.eumw.utils.key.KeyReader; @@ -63,6 +65,12 @@ public class CmsSignatureChecker */ private final Set trustAnchors = new HashSet<>(); + private final Set acceptedDigestAlgs = new HashSet<>(); + + private final Set acceptedSigAlgs = new HashSet<>(); + + private final Set acceptedCurves = new HashSet<>(); + /** holds the signed content after successful verification */ @Getter private Object verifiedContent; @@ -89,6 +97,25 @@ public CmsSignatureChecker(Collection trustAnchors) this.trustAnchors.addAll(Objects.requireNonNull(trustAnchors)); } + /** + * Constructor allowing configuration of accepted cryptographic algorithms. + * + * @param trustAnchors trust anchor certificates, null not permitted + * @param digestAlgs accepted digest algorithms as OID strings, null or empty for accepting any digest + * @param sigAlgs accepted signature algorithms as OID strings, null or empty for accepting any algorithm + * @param curves accepted elliptic curves as names, null or empty for accepting any curve + */ + public CmsSignatureChecker(Collection trustAnchors, + Collection digestAlgs, + Collection sigAlgs, + Collection curves) + { + this.trustAnchors.addAll(Objects.requireNonNull(trustAnchors)); + this.acceptedDigestAlgs.addAll(Objects.requireNonNullElse(digestAlgs, Set.of())); + this.acceptedSigAlgs.addAll(Objects.requireNonNullElse(sigAlgs, Set.of())); + this.acceptedCurves.addAll(Objects.requireNonNullElse(curves, Set.of())); + } + /** * checks the signature of the signed data and checks the validity of the certificates by validating them * against the current trust anchor @@ -144,12 +171,54 @@ private void checkEnvelopedSignature(InputStream signedCmsData, CertificationRev Store certificateStorage = cmsSignedData.getCertificates(); for ( SignerInformation signer : signers.getSigners() ) { + if (!acceptedDigestAlgs.isEmpty() && !acceptedDigestAlgs.contains(signer.getDigestAlgOID())) + { + throw new SignatureException("Unsupported digest algorithm detected"); + } + if (!acceptedSigAlgs.isEmpty() && !acceptedSigAlgs.contains(signer.getEncryptionAlgOID())) + { + throw new SignatureException("Unsupported signature algorithm detected"); + } + @SuppressWarnings("unchecked") X509CertificateHolder holder = (X509CertificateHolder)certificateStorage.getMatches(signer.getSID()) .iterator() .next(); ByteArrayInputStream certInputStream = getInputStreamOfCertificateData(holder); X509Certificate signatureVerificationCertificate = KeyReader.readX509Certificate(certInputStream); + + if (!acceptedCurves.isEmpty() && "EC".equals(signatureVerificationCertificate.getPublicKey().getAlgorithm())) + { + byte[] paramsFromCert; + try + { + paramsFromCert = holder.getSubjectPublicKeyInfo() + .getAlgorithm() + .getParameters() + .toASN1Primitive() + .getEncoded(); + } + catch (IOException e) + { + throw new SignatureException("Unable to extract curve parameters from certificate", e); + } + + boolean found = acceptedCurves.stream().map(c -> { + try + { + return ECNamedCurveTable.getByName(c).getEncoded(); + } + catch (IOException e) + { + return null; + } + }).anyMatch(b -> ByteUtil.equals(b, paramsFromCert)); + if (!found) + { + throw new SignatureException("Unsupported elliptic curve detected"); + } + } + validateCertificate(signatureVerificationCertificate, crlService); PublicKey publicKey = signatureVerificationCertificate.getPublicKey(); diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/InfoMapBuilder.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/InfoMapBuilder.java index a8cccc23..a1040af6 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/InfoMapBuilder.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/InfoMapBuilder.java @@ -21,7 +21,7 @@ import java.util.List; import java.util.Map; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/KeyArchive.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/KeyArchive.java index 9f012ac7..b34423a8 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/KeyArchive.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/KeyArchive.java @@ -12,9 +12,9 @@ import java.io.Serializable; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Lob; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; import de.governikus.eumw.poseidas.cardbase.AssertUtil; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PendingCertificateRequest.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PendingCertificateRequest.java index 4f48e6cc..8be09593 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PendingCertificateRequest.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PendingCertificateRequest.java @@ -12,14 +12,14 @@ import java.io.Serializable; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Lob; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; /** diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PermissionDataHandling.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PermissionDataHandling.java index 69edbb43..d50bbab5 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PermissionDataHandling.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/PermissionDataHandling.java @@ -26,7 +26,7 @@ import java.util.Optional; import java.util.Set; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Scope; @@ -487,6 +487,7 @@ public ManagementMessage triggerCertRenewal(String entityID) catch (Exception e) { SNMPTrapSender.sendSNMPTrap(SNMPConstants.TrapOID.CVC_TRAP_LAST_RENEWAL_STATUS, 1); + log.debug("unable to renew CVC", e); return GlobalManagementCodes.EC_UNEXPECTED_ERROR.createMessage("unable to renew CVC: " + e.getMessage()); } } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/RequestSignerCertificate.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/RequestSignerCertificate.java index c30a74ed..2d4cde80 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/RequestSignerCertificate.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/RequestSignerCertificate.java @@ -12,9 +12,9 @@ import java.io.Serializable; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.Lob; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.Lob; import lombok.Data; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ServiceProviderStatusService.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ServiceProviderStatusService.java index 62cb0445..8648cb9f 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ServiceProviderStatusService.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/ServiceProviderStatusService.java @@ -52,7 +52,10 @@ public ServiceProviderStatusService(TerminalPermissionAOBean facade, public ServiceProviderStatus getServiceProviderStatus(ServiceProviderType serviceProviderType) { - ServiceProviderStatus.ServiceProviderStatusBuilder builder = ServiceProviderStatus.builder(); + ServiceProviderStatus.ServiceProviderStatusBuilder builder = ServiceProviderStatus.builder() + .serviceProviderName(serviceProviderType.getName()) + .enabled(serviceProviderType.isEnabled()); + TerminalPermission terminalPermission = facade.getTerminalPermission(serviceProviderType.getCVCRefID()); if (terminalPermission == null) { @@ -62,12 +65,10 @@ public ServiceProviderStatus getServiceProviderStatus(ServiceProviderType servic CvcTlsCheck.CvcCheckResults cvcCheckResults = cvcTlsCheck.checkCvcProvider(serviceProviderType.getName()); - builder.serviceProviderName(serviceProviderType.getName()); boolean cvcPresent = cvcCheckResults.isCvcPresent(); if (cvcPresent) { - builder.enabled(serviceProviderType.isEnabled()) - .cvcPresent(true) + builder.cvcPresent(true) .cvcValidUntil(Optional.ofNullable(dateToLocalDate(terminalPermission.getNotOnOrAfter())) .map(d -> d.minusDays(1)) .orElse(null)) @@ -87,25 +88,25 @@ public ServiceProviderStatus getServiceProviderStatus(ServiceProviderType servic } } builder.blackListPresent(terminalPermission.getBlackListVersion() != null) - .blackListLastRetrieval(dateToLocalDateTime(terminalPermission.getBlackListStoreDate())) - .blackListDVCAAvailability(permissionDataHandling.pingRIService(serviceProviderType.getName())) - .masterListPresent(terminalPermission.getMasterListStoreDate() != null) - .masterListLastRetrieval(dateToLocalDateTime(terminalPermission.getMasterListStoreDate())) - .masterListDVCAAvailability(permissionDataHandling.pingPAService(serviceProviderType.getName())) - .defectListPresent(terminalPermission.getDefectListStoreDate() != null) - .defectListLastRetrieval(dateToLocalDateTime(terminalPermission.getDefectListStoreDate())) - .defectListDVCAAvailability(permissionDataHandling.pingPAService(serviceProviderType.getName())); - - X509Certificate pendingRSC = rscService.getRequestSignerCertificate(serviceProviderType.getName(), false); - if (pendingRSC != null) - { - builder.rscPendingPresent(true).rscAnyPresent(true); - } - X509Certificate currentRSC = rscService.getRequestSignerCertificate(serviceProviderType.getName(), true); - if (currentRSC != null) - { - builder.rscCurrentValidUntil(dateToLocalDate(currentRSC.getNotAfter())).rscAnyPresent(true); - } + .blackListLastRetrieval(dateToLocalDateTime(terminalPermission.getBlackListStoreDate())) + .blackListDVCAAvailability(permissionDataHandling.pingRIService(serviceProviderType.getName())) + .masterListPresent(terminalPermission.getMasterListStoreDate() != null) + .masterListLastRetrieval(dateToLocalDateTime(terminalPermission.getMasterListStoreDate())) + .masterListDVCAAvailability(permissionDataHandling.pingPAService(serviceProviderType.getName())) + .defectListPresent(terminalPermission.getDefectListStoreDate() != null) + .defectListLastRetrieval(dateToLocalDateTime(terminalPermission.getDefectListStoreDate())) + .defectListDVCAAvailability(permissionDataHandling.pingPAService(serviceProviderType.getName())); + + X509Certificate pendingRSC = rscService.getRequestSignerCertificate(serviceProviderType.getName(), false); + if (pendingRSC != null) + { + builder.rscPendingPresent(true).rscAnyPresent(true); + } + X509Certificate currentRSC = rscService.getRequestSignerCertificate(serviceProviderType.getName(), true); + if (currentRSC != null) + { + builder.rscCurrentValidUntil(dateToLocalDate(currentRSC.getNotAfter())).rscAnyPresent(true); + } return builder.build(); } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermission.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermission.java index 7135246d..d5155986 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermission.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermission.java @@ -17,17 +17,17 @@ import java.util.List; import java.util.Set; -import javax.annotation.Nullable; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.Lob; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.annotation.Nullable; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import de.governikus.eumw.poseidas.eidmodel.TerminalData; import lombok.Data; @@ -183,7 +183,7 @@ public TerminalData getFullCvc() } catch (IOException e) { - throw new IllegalArgumentException("unable to parse given cvc", e); + throw new IllegalArgumentException("unable to parse given CVC", e); } } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBean.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBean.java index a2b2dccd..a9df783f 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBean.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBean.java @@ -9,9 +9,6 @@ package de.governikus.eumw.poseidas.server.pki; -import static de.governikus.eumw.poseidas.config.model.ServiceProviderDetails.getNumberOfCHR; -import static de.governikus.eumw.poseidas.server.pki.CVCRequestHandler.getHolderReferenceStringOfPendingRequest; - import java.io.ByteArrayInputStream; import java.net.InetAddress; import java.net.UnknownHostException; @@ -35,7 +32,7 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Repository; @@ -47,6 +44,7 @@ import de.governikus.eumw.poseidas.cardbase.ArrayUtil; import de.governikus.eumw.poseidas.cardbase.AssertUtil; import de.governikus.eumw.poseidas.cardbase.asn1.npa.ECCVCertificate; +import de.governikus.eumw.poseidas.config.model.ServiceProviderDetails; import de.governikus.eumw.poseidas.eidmodel.TerminalData; import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; import de.governikus.eumw.poseidas.server.monitoring.SNMPConstants; @@ -634,8 +632,8 @@ public void storeCVCRequestCreated(String refID, } tp.setPendingRequest(pending); - Integer usedSequenceNumber = getNumberOfCHR(getHolderReferenceStringOfPendingRequest(pending)); - if (tp.getNextCvcSequenceNumber() == null && usedSequenceNumber != null) + Integer usedSequenceNumber = ServiceProviderDetails.getNumberOfCHR(CVCRequestHandler.getHolderReferenceStringOfPendingRequest(pending)); + if (usedSequenceNumber != null) { tp.setNextCvcSequenceNumber(usedSequenceNumber); } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/DvcaCertDescriptionService.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/DvcaCertDescriptionService.java index 151b500d..a14296e0 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/DvcaCertDescriptionService.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/DvcaCertDescriptionService.java @@ -11,7 +11,7 @@ import java.net.URISyntaxException; -import javax.xml.ws.BindingProvider; +import jakarta.xml.ws.BindingProvider; import dvca.v2.DVCACERTDESCRIPTION; import dvca.v2.DVCACertDescriptionService; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PKIServiceConnector.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PKIServiceConnector.java index 13e4c8ff..dcc2ff00 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PKIServiceConnector.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PKIServiceConnector.java @@ -35,8 +35,8 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509KeyManager; -import javax.xml.ws.BindingProvider; -import javax.xml.ws.WebServiceException; +import jakarta.xml.ws.BindingProvider; +import jakarta.xml.ws.WebServiceException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -95,6 +95,8 @@ public class PKIServiceConnector private static final char[] DUMMY_KEYPASS = "123456".toCharArray(); + private static final String DVCA_MTLS_ALIAS = "dvca-mtls"; + private static boolean sslContextLocked = false; private static long lockStealTime; @@ -176,7 +178,13 @@ private static KeyStore createKeystore(Key sslClientKey, LOG.error(entityID + ": KeyStore.load threw IOException even though no load was attempted", e); } X509Certificate[] clientCertChain = sslClientCert.toArray(new X509Certificate[sslClientCert.size()]); - clientKeyStore.setKeyEntry(entityID, sslClientKey, DUMMY_KEYPASS, clientCertChain); + // The BC JSSE Provider in version 1.66 manipulates the alias of the key store. For example 'test.alias' will be changed to '0.test.alias.1' + // Later when the private key entry will be loaded, the alias will be changed again. Theoretically the alias should be the same again, + // but unfortunately the method to build the alias search for '.' only from the beginning. So the alias '0.test.alias.1' + // will be just 'test' and not 'test.alias'. When an entity has '.' in the name, BC will not find the private key entry. + // Therefore, we change the alias to constant value. + // See ProvX509KeyManager#loadPrivateKeyEntry BC version 1.66 + clientKeyStore.setKeyEntry(DVCA_MTLS_ALIAS, sslClientKey, DUMMY_KEYPASS, clientCertChain); return clientKeyStore; } @@ -307,15 +315,18 @@ private KeyManager[] createKeyManager() throws NoSuchAlgorithmException, KeyStor KeyManagerFactory kmf; if (hsmMode) { + LOG.debug("HSM Mode is true. Use SunJSSE Provider"); kmf = KeyManagerFactory.getInstance("SUNX509", SecurityProvider.SUN_JSSE_PROVIDER); } else { + LOG.debug("HSM Mode is false. " + SecurityProvider.BOUNCY_CASTLE_JSSE_PROVIDER); kmf = KeyManagerFactory.getInstance("PKIX", SecurityProvider.BOUNCY_CASTLE_JSSE_PROVIDER); } kmf.init(clientCertAndKey, storePass); if (hsmMode) { + LOG.debug("HSM Mode is true. Use AliasKeyManager"); X509KeyManager origKM = (X509KeyManager)kmf.getKeyManagers()[0]; // force the key manager to use a defined key in case there is more than one KeyManager km = new AliasKeyManager(origKM, entityID); @@ -334,7 +345,7 @@ void setHttpsConnectionSetting(BindingProvider port, String uri) throws URISynta if (clientCertAndKey != null) { SSL_LOGGER.debug(entityID + ": Certificate for SSL client key:\n" - + certificateToString((X509Certificate)clientCertAndKey.getCertificate(entityID))); + + certificateToString((X509Certificate)clientCertAndKey.getCertificate(DVCA_MTLS_ALIAS))); } else { @@ -360,7 +371,7 @@ void setHttpsConnectionSetting(BindingProvider port, String uri) throws URISynta policy.setReceiveTimeout(MILLISECOND_FACTOR * timeout); conduit.setClient(policy); TLSClientParameters tlsClientParameters = new TLSClientParameters(); - tlsClientParameters.setSslContext(createSSLContext()); + tlsClientParameters.setSSLSocketFactory(createSSLContext().getSocketFactory()); tlsClientParameters.setCipherSuites(Arrays.asList(ENABLED_CIPHER_SUITES)); conduit.setTlsClientParameters(tlsClientParameters); } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PassiveAuthService.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PassiveAuthService.java index 4c168e30..62e01031 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PassiveAuthService.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/PassiveAuthService.java @@ -11,7 +11,7 @@ import java.net.URISyntaxException; -import javax.xml.ws.BindingProvider; +import jakarta.xml.ws.BindingProvider; import lombok.extern.slf4j.Slf4j; import uri.eac_pki_is_protocol._1.passiveAuth.dv.EACDVProtocolService; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/RestrictedIdService.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/RestrictedIdService.java index d4109f74..6d7101c4 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/RestrictedIdService.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/RestrictedIdService.java @@ -11,7 +11,7 @@ import java.net.URISyntaxException; -import javax.xml.ws.BindingProvider; +import jakarta.xml.ws.BindingProvider; import de.governikus.eumw.poseidas.gov2server.GovManagementException; import de.governikus.eumw.poseidas.gov2server.constants.admin.GlobalManagementCodes; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/TermAuthService.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/TermAuthService.java index 677a059f..38679588 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/TermAuthService.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/pki/caserviceaccess/TermAuthService.java @@ -17,7 +17,7 @@ import java.util.Map; import java.util.Map.Entry; -import javax.xml.ws.BindingProvider; +import jakarta.xml.ws.BindingProvider; import de.governikus.eumw.poseidas.eidmodel.TerminalData; import de.governikus.eumw.poseidas.gov2server.GovManagementException; diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/BlackListTimer.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/BlackListTimer.java index 0ae79dea..56da2db7 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/BlackListTimer.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/BlackListTimer.java @@ -66,12 +66,12 @@ Trigger getBlackListTrigger() log.debug("First delta Black List timer task will be executed with an initial delay of {} milliseconds", initialDelay); log.debug("Black List timer task will be executed at {}", date); - return date; + return date.toInstant(); } Instant nextExecutiontime = lastCompletion.toInstant().plusMillis(getDeltaBlackListTimer()); Date date = Date.from(nextExecutiontime); log.debug("Black List timer task will be executed at {}", date); - return date; + return date.toInstant(); }; } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CrlRenewalTimer.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CrlRenewalTimer.java index 97c827f1..0c5c70de 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CrlRenewalTimer.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CrlRenewalTimer.java @@ -68,12 +68,12 @@ Trigger getCrlTrigger() Date date = new Date(triggerContext.getClock().millis() + initialDelay); log.debug("First CRL timer task will executed with an initial delay of {} milliseconds", initialDelay); log.debug("CRL renewal timer task will be executed at {}", date); - return date; + return date.toInstant(); } Instant nextExecutiontime = lastCompletion.toInstant().plusMillis(getCrlRenewalTimer()); Date date = Date.from(nextExecutiontime); log.debug("CRL renewal timer task will be executed at {}", date); - return date; + return date.toInstant(); }; } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CvcRenewalTimer.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CvcRenewalTimer.java index 4c8d75cc..9c13a3a7 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CvcRenewalTimer.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/CvcRenewalTimer.java @@ -65,12 +65,12 @@ Trigger getCvcRenewalTrigger() Date date = new Date(triggerContext.getClock().millis() + initialDelay); log.debug("First CVC renewal timer task will executed with an initial delay of {} milliseconds", initialDelay); log.debug("CVC renewal timer task will be executed at {}", date); - return date; + return date.toInstant(); } Instant nextExecutiontime = lastCompletion.toInstant().plusMillis(getCvcRenewalTimer()); Date date = Date.from(nextExecutiontime); log.debug("CVC renewal timer task will be executed at {}", date); - return date; + return date.toInstant(); }; } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/GlobalListTimer.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/GlobalListTimer.java index 4115a10c..c87a1c78 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/GlobalListTimer.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/GlobalListTimer.java @@ -63,12 +63,12 @@ Trigger getGlobalListTrigger() Date date = new Date(triggerContext.getClock().millis() + initialDelay); log.debug("First global list timer task will executed with an initial delay of {} milliseconds", initialDelay); log.debug("Global list timer task will be executed at {}", date); - return date; + return date.toInstant(); } Instant nextExecutiontime = lastCompletion.toInstant().plusMillis(getGlobalListTimer()); Date date = Date.from(nextExecutiontime); log.debug("Global list timer task will be executed at {}", date); - return date; + return date.toInstant(); }; } diff --git a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/RequestSignerCvcRenewTimer.java b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/RequestSignerCvcRenewTimer.java index dcdb1093..1796c087 100644 --- a/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/RequestSignerCvcRenewTimer.java +++ b/poseidas/src/main/java/de/governikus/eumw/poseidas/server/timer/RequestSignerCvcRenewTimer.java @@ -1,5 +1,6 @@ package de.governikus.eumw.poseidas.server.timer; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; @@ -25,7 +26,6 @@ import de.governikus.eumw.config.EidasMiddlewareConfig; import de.governikus.eumw.config.ServiceProviderType; -import de.governikus.eumw.poseidas.cardbase.asn1.ASN1; import de.governikus.eumw.poseidas.cardserver.certrequest.CertificateRequest; import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; import de.governikus.eumw.poseidas.server.pki.PendingCertificateRequest; @@ -170,7 +170,7 @@ private boolean isPendingRequestReusable(PendingCertificateRequest pendingCertif String outerAuthorityReferenceString; try { - CertificateRequest certificateRequest = new CertificateRequest(new ASN1(pendingCertificateRequest.getRequestData()).getValue()); + CertificateRequest certificateRequest = new CertificateRequest(new ByteArrayInputStream(pendingCertificateRequest.getRequestData())); outerAuthorityReferenceString = certificateRequest.getOuterAuthorityReferenceString(); } catch (IOException e) diff --git a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.jxb b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.jxb index 3353bb7d..30327b7f 100644 --- a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.jxb +++ b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.jxb @@ -1,8 +1,8 @@ - + xmlns:xjc="https://jakarta.ee/xml/ns/jaxb/xjc"> diff --git a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.wsb b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.wsb index d6386a3f..e6b313e0 100644 --- a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.wsb +++ b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/passiveAuth.dv.wsb @@ -1,7 +1,7 @@ diff --git a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.jxb b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.jxb index ca365f63..66f87f85 100644 --- a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.jxb +++ b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.jxb @@ -1,8 +1,8 @@ - + xmlns:xjc="https://jakarta.ee/xml/ns/jaxb/xjc"> diff --git a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.wsb b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.wsb index 4b332b5e..873b34a4 100644 --- a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.wsb +++ b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/restrictedId.dv.wsb @@ -1,7 +1,7 @@ - diff --git a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.jxb b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.jxb index af868535..17637224 100644 --- a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.jxb +++ b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.jxb @@ -1,8 +1,8 @@ - + xmlns:xjc="https://jakarta.ee/xml/ns/jaxb/xjc"> diff --git a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.wsb b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.wsb index 9953021f..f9791277 100644 --- a/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.wsb +++ b/poseidas/src/main/resources/META-INF/wsdl/CA-Services/termAuth.dv.wsb @@ -1,6 +1,6 @@ diff --git a/poseidas/src/main/resources/templates/fragments/form.html b/poseidas/src/main/resources/templates/fragments/form.html index b0b53e11..aafc3076 100644 --- a/poseidas/src/main/resources/templates/fragments/form.html +++ b/poseidas/src/main/resources/templates/fragments/form.html @@ -42,13 +42,17 @@ -

+
+
+
+ +
- +

@@ -81,16 +85,17 @@

-
+
- +

+

diff --git a/poseidas/src/main/resources/templates/pages/details.html b/poseidas/src/main/resources/templates/pages/details.html index de7d2ea5..6333940f 100644 --- a/poseidas/src/main/resources/templates/pages/details.html +++ b/poseidas/src/main/resources/templates/pages/details.html @@ -138,9 +138,12 @@

Initial CVC request

th:action="@{'/admin-interface/details/initialRequest?entityid=' + ${#uris.escapeQueryParam(entityID)}}" th:object="${form}" method="post" id="initial-request-form">
-
-
-
+
+
+
+
+ *Required fields +

Certificates and key pairs

-
- +
+
+ + Attention: HSM is active, signature key pair from HSM is used instead of potentially configured value +
+
+
diff --git a/poseidas/src/main/resources/templates/pages/keymanagement/createFromKeystore.html b/poseidas/src/main/resources/templates/pages/keymanagement/createFromKeystore.html index d4e3305c..46f08330 100644 --- a/poseidas/src/main/resources/templates/pages/keymanagement/createFromKeystore.html +++ b/poseidas/src/main/resources/templates/pages/keymanagement/createFromKeystore.html @@ -32,7 +32,7 @@

The key store doe

-
+
@@ -67,7 +67,7 @@
Extract key pair

-
+
diff --git a/poseidas/src/main/resources/templates/pages/keymanagement/index.html b/poseidas/src/main/resources/templates/pages/keymanagement/index.html index ca590ab6..e8738aa7 100644 --- a/poseidas/src/main/resources/templates/pages/keymanagement/index.html +++ b/poseidas/src/main/resources/templates/pages/keymanagement/index.html @@ -108,7 +108,7 @@
Upload key store

-
+
@@ -174,7 +174,7 @@
Upload

-
+

diff --git a/poseidas/src/main/resources/templates/pages/metadata/index.html b/poseidas/src/main/resources/templates/pages/metadata/index.html index 16f5da18..30fe161d 100644 --- a/poseidas/src/main/resources/templates/pages/metadata/index.html +++ b/poseidas/src/main/resources/templates/pages/metadata/index.html @@ -32,7 +32,7 @@

Metadata files

Entity ID signature valid - + @@ -41,7 +41,7 @@

Metadata files

+ th:text="${meta.checkedAsValid == null ? 'unsigned' : meta.checkedAsValid ? '✔' : '❌'}"/> eID service provider configuration

The DVCA configuration to use

-
+
+
+ + Attention: HSM is active, DVCA client authentication key pair from HSM is used instead of potentially configured value +
+
+
- + xmlns:xjc="https://jakarta.ee/xml/ns/jaxb/xjc"> diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelectorTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelectorTest.java index 337e2b04..511f83f2 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelectorTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/cardbase/npa/InfoSelectorTest.java @@ -37,6 +37,10 @@ class InfoSelectorTest private static final byte[] efCardAccessWithoutCa2 = Hex.parse("31820110300d060804007f00070202020201023012060a04007f000702020302020201010201413012060a04007f0007020203020202010302014a3012060a04007f0007020204020202010202010d301b060b04007f000702020b010203300902010102010002010102014a301c060904007f000702020302300c060704007f0007010202010d020141301c060904007f000702020302300c060704007f0007010202010d02014a302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c303e060804007f000702020831323012060a04007f00070202030202020102020145301c060904007f000702020302300c060704007f0007010202010d020145"); + private static final byte[] efCardAccessWithUnknownCurveId = Hex.parse("3181c13012060a04007f0007020204020202010202010d300d060804007f00070202020201023012060a04007f00070202030202020102020129301c060904007f000702020302300c060704007f00070102020142020129303e060804007f000702020831323012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c"); + + private static final byte[] efCardAccessWithExplicitDomainParameters = Hex.parse("3181e53012060a04007f0007020204020202010202010d300d060804007f00070202020201023012060a04007f000702020302020201020201293040060904007F000702020302303006072a8648ce3d02013025020101300D06072a8648ce3d01010202008030060401000401000403040840020102020101020129303e060804007f000702020831323012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c"); + private static Stream parameterSource() { return Stream.of(newEFCardAccess, @@ -45,6 +49,11 @@ private static Stream parameterSource() efCardAccessWithCa2And3SameKeyIdReverseOrder); } + private static Stream parameterSourceUnsupported() + { + return Stream.of(efCardAccessWithUnknownCurveId, efCardAccessWithExplicitDomainParameters); + } + @ParameterizedTest @MethodSource("parameterSource") void testNewEFCardAccess(byte[] source) throws IOException @@ -70,4 +79,17 @@ void testEFCardAccessNoCa2() throws IOException Assertions.assertThrows(Exception.class, () -> InfoSelector.selectCAData(caInfoList, caDomParamList)); } + + @ParameterizedTest + @MethodSource("parameterSourceUnsupported") + void testEFCardAccessUnsupported() throws IOException + { + SecurityInfos efCardAccess = new SecurityInfos(); + efCardAccess.decode(efCardAccessWithExplicitDomainParameters); + + List caInfoList = efCardAccess.getChipAuthenticationInfo(); + List caDomParamList = efCardAccess.getChipAuthenticationDomainParameterInfo(); + + Assertions.assertNull(InfoSelector.selectCAData(caInfoList, caDomParamList)); + } } diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/CVCControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/CVCControllerTest.java index 4cfd504d..8e308c5c 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/CVCControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/CVCControllerTest.java @@ -180,9 +180,9 @@ void testInitialRequestSuccess() throws IOException }); HtmlPage serviceProviderPage = getServiceProviderPage(); - setTextValue(serviceProviderPage, "Country-code", "DE"); - setTextValue(serviceProviderPage, "CHR-Mnemonic", "CHR"); - setNumberValue(serviceProviderPage, "Sequence-number", 42); + setTextValue(serviceProviderPage, "countryCode", "DE"); + setTextValue(serviceProviderPage, "chrMnemonic", "CHR"); + setNumberValue(serviceProviderPage, "sequenceNumber", 42); HtmlPage requestedCvcPage = submitFormById(serviceProviderPage, "initial-request-form"); assertMessageAlert(requestedCvcPage, "Initial request succeeded"); } @@ -197,9 +197,9 @@ void testInitialRequestFailed() throws IOException .thenReturn(GlobalManagementCodes.INTERNAL_ERROR.createMessage()); HtmlPage serviceProviderPage = getServiceProviderPage(); - setTextValue(serviceProviderPage, "Country-code", "DE"); - setTextValue(serviceProviderPage, "CHR-Mnemonic", "CHR"); - setNumberValue(serviceProviderPage, "Sequence-number", 42); + setTextValue(serviceProviderPage, "countryCode", "DE"); + setTextValue(serviceProviderPage, "chrMnemonic", "CHR"); + setNumberValue(serviceProviderPage, "sequenceNumber", 42); HtmlPage requestedCvcPage = submitFormById(serviceProviderPage, "initial-request-form"); assertErrorAlert(requestedCvcPage, "Initial request failed"); } diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/DvcaControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/DvcaControllerTest.java index 5095b26e..9e1f8677 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/DvcaControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/DvcaControllerTest.java @@ -54,7 +54,7 @@ class DvcaControllerTest extends WebAdminTestBase private final ConfigurationService configurationService; - private static final String NAME_ID = "Name"; + private static final String NAME_ID = "name"; private static final String DVCA_SERVER_CERT_ID = "serverSSLCertificateName"; @@ -62,13 +62,13 @@ class DvcaControllerTest extends WebAdminTestBase private static final String ML_TRUSTANCHOR_CERT_ID = "masterListTrustAnchorCertificateName"; - private static final String TERMINALAUTHENTICATION_SERVICE_URL_ID = "Terminal-Authentication-service-URL"; + private static final String TERMINALAUTHENTICATION_SERVICE_URL_ID = "terminalAuthServiceUrl"; - private static final String RESTRICTED_ID_SERVICE_URL_ID = "Restricted-Identification-service-URL"; + private static final String RESTRICTED_ID_SERVICE_URL_ID = "restrictedIdServiceUrl"; - private static final String PASSIVEAUTHENTICATION_SERVICE_URL_ID = "Passive-Authentication-service-URL"; + private static final String PASSIVEAUTHENTICATION_SERVICE_URL_ID = "passiveAuthServiceUrl"; - private static final String DVCA_CERTIFICATE_DESCRIPTION_SERVICE_URL_ID = "CVC-description-service-URL"; + private static final String DVCA_CERTIFICATE_DESCRIPTION_SERVICE_URL_ID = "dvcaCertificateDescrptionServiceUrl"; @Autowired diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidControllerTest.java index 0d0b3e8d..3a780589 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidControllerTest.java @@ -46,7 +46,7 @@ class EidControllerTest extends WebAdminTestBase private final ConfigurationService configurationService; - private final static String ALLOWED_EID_TYPES_FIELD_ID = "Allowed-eID-means"; + private final static String ALLOWED_EID_TYPES_FIELD_ID = "allowedEidMeans"; @Autowired public EidControllerTest(ConfigurationService configurationService) diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidasControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidasControllerTest.java index 0da57a08..3f9b873e 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidasControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/EidasControllerTest.java @@ -10,30 +10,43 @@ package de.governikus.eumw.poseidas.config; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.nio.file.Files; +import java.security.KeyStore; import java.util.Optional; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; -import org.springframework.test.context.junit.jupiter.SpringExtension; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSelect; import de.governikus.eumw.config.CertificateType; import de.governikus.eumw.config.EidasMiddlewareConfig; import de.governikus.eumw.config.KeyPairType; +import de.governikus.eumw.config.KeyStoreType; +import de.governikus.eumw.config.KeyStoreTypeType; import de.governikus.eumw.config.ServiceProviderType; +import de.governikus.eumw.eidasstarterkit.EidasSigner; import de.governikus.eumw.poseidas.config.base.TestConfiguration; import de.governikus.eumw.poseidas.config.base.WebAdminTestBase; import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; +import de.governikus.eumw.poseidas.server.pki.HSMServiceHolder; +import de.governikus.eumw.utils.key.KeyStoreSupporter; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -42,7 +55,6 @@ * Test the admin ui for the timer config */ @Slf4j -@ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {"server.servlet.context-path=/"}) @Import(TestConfiguration.class) @DisplayName("Test eidas config page") @@ -59,27 +71,27 @@ class EidasControllerTest extends WebAdminTestBase private static final String PUBLIC_SP_SELECT_ID = "Public-service-provider"; - private static final String SERVER_URL_ID = "Server-URL"; + private static final String SERVER_URL_ID = "serverUrl"; - private static final String COUNTRY_CODE_ID = "Country-code"; + private static final String COUNTRY_CODE_ID = "countryCode"; - private static final String CONTACT_PERSON_COMPANY_NAME_ID = "Company-name"; + private static final String CONTACT_PERSON_COMPANY_NAME_ID = "contactPersonCompanyName"; - private static final String CONTACT_PERSON_NAME_ID = "Given-name"; + private static final String CONTACT_PERSON_NAME_ID = "contactPersonName"; - private static final String CONTACT_PERSON_SURNAME_ID = "Surname"; + private static final String CONTACT_PERSON_SURNAME_ID = "contactPersonSurname"; - private static final String CONTACT_PERSON_EMAIL_ID = "Email"; + private static final String CONTACT_PERSON_EMAIL_ID = "contactPersonMail"; - private static final String CONTACT_PERSON_PHONE_ID = "Phone"; + private static final String CONTACT_PERSON_PHONE_ID = "contactPersonTel"; - private static final String ORGANIZATION_DISPLAYNAME_ID = "Display-name"; + private static final String ORGANIZATION_DISPLAYNAME_ID = "organizationDisplayname"; - private static final String ORGANIZATION_NAME_ID = "Name"; + private static final String ORGANIZATION_NAME_ID = "organizationName"; - private static final String ORGANIZATION_LANGUAGE_ID = "Language"; + private static final String ORGANIZATION_LANGUAGE_ID = "organizationLanguage"; - private static final String ORGANIZATION_URL_ID = "URL"; + private static final String ORGANIZATION_URL_ID = "organizationUrl"; private static final String SIGNATURE_KEYPAIR_ID = "signatureKeyPairName"; @@ -87,6 +99,9 @@ class EidasControllerTest extends WebAdminTestBase private static final String SIGN_METADATA_ID = "Sign-metadata"; + @MockBean + private HSMServiceHolder hsmServiceHolder; + @Autowired public EidasControllerTest(ConfigurationService configurationService) { @@ -120,7 +135,6 @@ void testWrongValues() throws IOException assertValidationMessagePresent(eidasConfigPage, PUBLIC_SP_SELECT_ID, PROVIDER_DOES_NOT_EXIST, HAS_TO_BE_SELECTED); assertValidationMessagePresent(eidasConfigPage, SERVER_URL_ID, "May not be empty"); assertValidationMessagePresent(eidasConfigPage, COUNTRY_CODE_ID, "A Country code has exactly two characters"); - assertValidationMessagePresent(eidasConfigPage, SIGNATURE_KEYPAIR_ID, KEY_PAIR_DOES_NOT_EXIST, HAS_TO_BE_SELECTED); assertTrue(configurationService.getConfiguration().map(EidasMiddlewareConfig::getEidasConfiguration).isEmpty()); } @@ -134,8 +148,11 @@ void testCorrectValue() throws IOException // Configure temporary service provider and key pairs EidasMiddlewareConfig.KeyData keyData = new EidasMiddlewareConfig.KeyData(); + + keyData.getKeyStore() + .add(new KeyStoreType("", Files.readAllBytes(TEST_KEY_STORE_FILE.toPath()), KeyStoreTypeType.JKS, "123456")); keyData.getKeyPair().add(new KeyPairType("KP1", "", "", "")); - keyData.getKeyPair().add(new KeyPairType("KP2", "", "", "")); + keyData.getKeyPair().add(new KeyPairType("KP2", "jks-keystore", "123456", "")); keyData.getKeyPair().add(new KeyPairType("KP3", "", "", "")); keyData.getCertificate().add(new CertificateType("C1", null, "", "")); @@ -199,4 +216,134 @@ void testCorrectValue() throws IOException assertTrue(eidasConfiguration.isDoSign()); } + + @SneakyThrows + @ParameterizedTest + @CsvSource({"/configuration/rsa-2048.p12,rsa-2048,The key pair does not fulfill the eIDAS crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=rsa-2048 and serial 1702297893 does not meet specified minimum RSA key size of 3072.", + "/configuration/secp224r1.p12,secp224r1,The key pair does not fulfill the eIDAS crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=secp224r1 and serial 691177073619503856166633885441189605629960653141 does not meet specified minimum EC key size of 256.", + "/configuration/brainpoolP512r1-explicit.p12,brainpoolP512r1,The signature certificate does not meet the crypto requirements: The key pair does not fulfill the eIDAS crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=BPR-CSCA, OU=Autent, O=Governikus, L=Bremen, C=DE and serial 30727073461927801660542095644293943332594583035 does not use a named curve."}) + void testExistingInvalidKey(String invalidKeyStore, String invalidKeyStoreAlias, String expectedError) + { + assertTrue(configurationService.getConfiguration().map(EidasMiddlewareConfig::getEidasConfiguration).isEmpty()); + + // Prepare a configuration with an invalid key and an RSA 4096 key + EidasMiddlewareConfig.KeyData keyData = new EidasMiddlewareConfig.KeyData(); + + byte[] invalidKeyStoreBytes = EidasControllerTest.class.getResourceAsStream(invalidKeyStore).readAllBytes(); + keyData.getKeyStore() + .add(new KeyStoreType(invalidKeyStoreAlias, invalidKeyStoreBytes, KeyStoreTypeType.PKCS_12, "123456")); + keyData.getKeyPair() + .add(new KeyPairType(invalidKeyStoreAlias, invalidKeyStoreAlias, "123456", invalidKeyStoreAlias)); + + byte[] validKeyStoreBytes = EidasControllerTest.class.getResourceAsStream("/configuration/keystore.p12") + .readAllBytes(); + keyData.getKeyStore() + .add(new KeyStoreType("pkcs12-keystore", validKeyStoreBytes, KeyStoreTypeType.PKCS_12, "123456")); + keyData.getKeyPair().add(new KeyPairType("pkcs12-keystore", "pkcs12-keystore", "123456", "pkcs12-keystore")); + + // Set the invalid key in the eidas configuration + EidasMiddlewareConfig.EidasConfiguration eidasConfiguration = new EidasMiddlewareConfig.EidasConfiguration(); + eidasConfiguration.setSignatureKeyPairName(invalidKeyStoreAlias); + + // Add necessary data for the eidas page + EidasMiddlewareConfig.EidConfiguration eidConfiguration = new EidasMiddlewareConfig.EidConfiguration(); + eidConfiguration.getServiceProvider().add(new ServiceProviderType("TestSP", true, "KP", "NONE", "NONE")); + eidasConfiguration.setCountryCode("DE"); + eidasConfiguration.setPublicServiceProviderName("TestSP"); + EidasMiddlewareConfig eidasMiddlewareConfig = new EidasMiddlewareConfig(); + eidasMiddlewareConfig.setEidConfiguration(eidConfiguration); + eidasMiddlewareConfig.setKeyData(keyData); + eidasMiddlewareConfig.setEidasConfiguration(eidasConfiguration); + eidasMiddlewareConfig.setServerUrl("https://localhost"); + configurationService.saveConfiguration(eidasMiddlewareConfig, false); + + // Open the page and check that the key is invalid + HtmlPage eidasConfigPage = getEidasConfigPage(); + assertErrorAlert(eidasConfigPage, expectedError); + + // Verify that this can be fixed in the UI + setSelectValue(eidasConfigPage, "signatureKeyPairName", "pkcs12-keystore"); + eidasConfigPage = submitAnyForm(eidasConfigPage); + assertFalse(eidasConfigPage.asNormalizedText() + .contains("The signature certificate does not meet the crypto requirements")); + HtmlSelect signatureKeyPairName = (HtmlSelect)eidasConfigPage.getElementById("signatureKeyPairName"); + Assertions.assertEquals("pkcs12-keystore", signatureKeyPairName.getSelectedOptions().get(0).getText()); + } + + @SneakyThrows + @ParameterizedTest + @CsvSource({"/configuration/rsa-2048.p12,rsa-2048,The key pair does not fulfill the eIDAS crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=rsa-2048 and serial 1702297893 does not meet specified minimum RSA key size of 3072.", + "/configuration/secp224r1.p12,secp224r1,The key pair does not fulfill the eIDAS crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=secp224r1 and serial 691177073619503856166633885441189605629960653141 does not meet specified minimum EC key size of 256.", + "/configuration/brainpoolP512r1-explicit.p12,brainpoolP512r1,The signature certificate does not meet the crypto requirements: The key pair does not fulfill the eIDAS crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=BPR-CSCA, OU=Autent, O=Governikus, L=Bremen, C=DE and serial 30727073461927801660542095644293943332594583035 does not use a named curve."}) + void testSelectInvalidKey(String invalidKeyStore, String invalidKeyStoreAlias, String expectedError) + { + assertTrue(configurationService.getConfiguration().map(EidasMiddlewareConfig::getEidasConfiguration).isEmpty()); + + // Prepare a configuration with an invalid key and an RSA 4096 key + EidasMiddlewareConfig.KeyData keyData = new EidasMiddlewareConfig.KeyData(); + + byte[] invalidKeyStoreBytes = EidasControllerTest.class.getResourceAsStream(invalidKeyStore).readAllBytes(); + keyData.getKeyStore() + .add(new KeyStoreType(invalidKeyStoreAlias, invalidKeyStoreBytes, KeyStoreTypeType.PKCS_12, "123456")); + keyData.getKeyPair() + .add(new KeyPairType(invalidKeyStoreAlias, invalidKeyStoreAlias, "123456", invalidKeyStoreAlias)); + + byte[] validKeyStoreBytes = EidasControllerTest.class.getResourceAsStream("/configuration/keystore.p12") + .readAllBytes(); + keyData.getKeyStore() + .add(new KeyStoreType("pkcs12-keystore", validKeyStoreBytes, KeyStoreTypeType.PKCS_12, "123456")); + keyData.getKeyPair().add(new KeyPairType("pkcs12-keystore", "pkcs12-keystore", "123456", "pkcs12-keystore")); + + // Set the valid key in the eidas configuration + EidasMiddlewareConfig.EidasConfiguration eidasConfiguration = new EidasMiddlewareConfig.EidasConfiguration(); + eidasConfiguration.setSignatureKeyPairName("pkcs12-keystore"); + + EidasMiddlewareConfig.EidConfiguration eidConfiguration = new EidasMiddlewareConfig.EidConfiguration(); + eidConfiguration.getServiceProvider().add(new ServiceProviderType("TestSP", true, "KP", "NONE", "NONE")); + eidasConfiguration.setCountryCode("DE"); + eidasConfiguration.setPublicServiceProviderName("TestSP"); + EidasMiddlewareConfig eidasMiddlewareConfig = new EidasMiddlewareConfig(); + eidasMiddlewareConfig.setEidConfiguration(eidConfiguration); + eidasMiddlewareConfig.setKeyData(keyData); + eidasMiddlewareConfig.setEidasConfiguration(eidasConfiguration); + eidasMiddlewareConfig.setServerUrl("https://localhost"); + configurationService.saveConfiguration(eidasMiddlewareConfig, false); + + // Open the page and check that the key is valid + HtmlPage eidasConfigPage = getEidasConfigPage(); + assertFalse(eidasConfigPage.asNormalizedText() + .contains("The signature certificate does not meet the crypto requirements")); + + // Select the invalid key and try to save + setSelectValue(eidasConfigPage, "signatureKeyPairName", invalidKeyStoreAlias); + eidasConfigPage = submitAnyForm(eidasConfigPage); + + // Check that the error message is visible + assertValidationMessagePresent(eidasConfigPage, "signatureKeyPairName", expectedError); + + // Check that the config was not saved by reloading the page + eidasConfigPage = getWebClient().getPage(getRequestUrl("/eidasConfiguration")); + HtmlSelect signatureKeyPairName = (HtmlSelect)eidasConfigPage.getElementById("signatureKeyPairName"); + Assertions.assertEquals("pkcs12-keystore", signatureKeyPairName.getSelectedOptions().get(0).getText()); + } + + @SneakyThrows + @ParameterizedTest + @CsvSource({"/configuration/rsa-2048.p12,rsa-2048,The signature certificate in the HSM does not meet the crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=rsa-2048 and serial 1702297893 does not meet specified minimum RSA key size of 3072.", + "/configuration/secp224r1.p12,secp224r1,The signature certificate in the HSM does not meet the crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=secp224r1 and serial 691177073619503856166633885441189605629960653141 does not meet specified minimum EC key size of 256.", + "/configuration/brainpoolP512r1-explicit.p12,brainpoolP512r1,The signature certificate in the HSM does not meet the crypto requirements: Certificate is not valid for that purpose because of reason Certificate with subject CN=BPR-CSCA, OU=Autent, O=Governikus, L=Bremen, C=DE and serial 30727073461927801660542095644293943332594583035 does not use a named curve."}) + void testInvalidKeyInHsm(String keyStore, String alias, String expectedError) + { + KeyStore hsmKeyStore = KeyStoreSupporter.readKeyStore(EidasControllerTest.class.getResourceAsStream(keyStore) + .readAllBytes(), + KeyStoreSupporter.KeyStoreType.PKCS12, + "123456"); + KeyStore.Entry entry = hsmKeyStore.getEntry(alias, new KeyStore.PasswordProtection("123456".toCharArray())); + hsmKeyStore.setEntry(EidasSigner.SAML_SIGNING, entry, new KeyStore.PasswordProtection("123456".toCharArray())); + Mockito.when(hsmServiceHolder.getKeyStore()).thenReturn(hsmKeyStore); + + HtmlPage eidasConfigPage = getEidasConfigPage(); + assertErrorAlert(eidasConfigPage, expectedError); + + } } diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationControllerTest.java index 2c4c2d36..bed1258e 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ImportExportConfigurationControllerTest.java @@ -99,7 +99,7 @@ void testWhenWrongFileForInputThenReturnErrorMessage() throws Exception HtmlPage configurationPage = getConfigurationPage(); HtmlForm uploadForm = configurationPage.getForms().get(0); HtmlFileInput inputField = uploadForm.getInputByName("configurationFile"); - String pathToConfigFile = Objects.requireNonNull(ImportExportConfigurationControllerTest.class.getResource("/configuration/demo_epa.xml")) + String pathToConfigFile = Objects.requireNonNull(ImportExportConfigurationControllerTest.class.getResource("/configuration/metadata-9443.xml")) .toExternalForm(); inputField.setValueAttribute(pathToConfigFile); HtmlPage savedConfig = configurationPage.getHtmlElementById("save").click(); diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/KeymanagementControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/KeymanagementControllerTest.java index af786023..ec67775c 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/KeymanagementControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/KeymanagementControllerTest.java @@ -59,13 +59,13 @@ class KeymanagementControllerTest extends WebAdminTestBase { - public static final String CERTIFICATE_UPLOAD_NAME_ID = "Certificate-name"; + public static final String CERTIFICATE_UPLOAD_NAME_ID = "certificateName"; public static final String CERTIFICATE_UPLOAD_FILE_INPUT_ID = "certificate-upload"; public static final String KEY_STORE_UPLOAD_FORM_ID = "KeyStoreUpload"; - public static final String KEYSTORE_UPLOAD_NAME_ID = "Key-store-name"; + public static final String KEYSTORE_UPLOAD_NAME_ID = "keyStoreName"; public static final String KEYSTORE_UPLOAD_PASSWORD_ID = "Key-store-password"; @@ -73,7 +73,7 @@ class KeymanagementControllerTest extends WebAdminTestBase public static final String KEYSTORE_UPLOAD_FILE_ID = "keystore-upload"; - public static final String EXTRACT_CERTIFICATE_NAME_ID = "Certificate-name"; + public static final String EXTRACT_CERTIFICATE_NAME_ID = "certificateName"; public static final String EXTRACT_CERTIFICATE_ALIAS_ID = "certalias"; @@ -81,7 +81,7 @@ class KeymanagementControllerTest extends WebAdminTestBase public static final String EXTRACT_KEY_PAIR_FORM_ID = "extractKeyPairForm"; - public static final String EXTRACT_KEY_PAIR_NAME_ID = "Key-pair-name"; + public static final String EXTRACT_KEY_PAIR_NAME_ID = "keyPairName"; public static final String EXTRACT_KEY_PAIR_ALIAS_ID = "keyPairalias"; diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/MetadataControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/MetadataControllerTest.java index 3b894dec..8c31a675 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/MetadataControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/MetadataControllerTest.java @@ -9,24 +9,81 @@ package de.governikus.eumw.poseidas.config; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyStore; +import java.security.PrivateKey; import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Base64; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.xml.security.algorithms.MessageDigestAlgorithm; +import org.apache.xml.security.signature.XMLSignature; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mockito; +import org.opensaml.saml.common.SAMLObjectContentReference; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.ext.saml2alg.SigningMethod; +import org.opensaml.saml.ext.saml2alg.impl.SigningMethodBuilder; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EncryptionMethod; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.Extensions; +import org.opensaml.saml.saml2.metadata.KeyDescriptor; +import org.opensaml.saml.saml2.metadata.NameIDFormat; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml.saml2.metadata.impl.AssertionConsumerServiceBuilder; +import org.opensaml.saml.saml2.metadata.impl.EncryptionMethodBuilder; +import org.opensaml.saml.saml2.metadata.impl.EntityDescriptorBuilder; +import org.opensaml.saml.saml2.metadata.impl.EntityDescriptorMarshaller; +import org.opensaml.saml.saml2.metadata.impl.ExtensionsBuilder; +import org.opensaml.saml.saml2.metadata.impl.KeyDescriptorBuilder; +import org.opensaml.saml.saml2.metadata.impl.NameIDFormatBuilder; +import org.opensaml.saml.saml2.metadata.impl.SPSSODescriptorBuilder; +import org.opensaml.security.credential.UsageType; +import org.opensaml.security.x509.BasicX509Credential; +import org.opensaml.xmlsec.encryption.support.EncryptionConstants; +import org.opensaml.xmlsec.signature.DigestMethod; +import org.opensaml.xmlsec.signature.KeyInfo; +import org.opensaml.xmlsec.signature.Signature; +import org.opensaml.xmlsec.signature.X509Data; +import org.opensaml.xmlsec.signature.impl.DigestMethodBuilder; +import org.opensaml.xmlsec.signature.impl.KeyInfoBuilder; +import org.opensaml.xmlsec.signature.impl.SignatureBuilder; +import org.opensaml.xmlsec.signature.impl.X509CertificateBuilder; +import org.opensaml.xmlsec.signature.impl.X509DataBuilder; +import org.opensaml.xmlsec.signature.support.SignatureConstants; +import org.opensaml.xmlsec.signature.support.Signer; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.w3c.dom.Element; import com.gargoylesoftware.htmlunit.UnexpectedPage; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; @@ -39,11 +96,21 @@ import com.gargoylesoftware.htmlunit.html.HtmlTextArea; import de.governikus.eumw.config.CertificateType; +import de.governikus.eumw.config.ConnectorMetadataType; import de.governikus.eumw.config.EidasMiddlewareConfig; +import de.governikus.eumw.eidascommon.Utils; +import de.governikus.eumw.eidasstarterkit.EidasSaml; import de.governikus.eumw.poseidas.config.base.TestConfiguration; +import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationException; import de.governikus.eumw.poseidas.service.MetadataService; import de.governikus.eumw.utils.key.KeyReader; +import de.governikus.eumw.utils.key.KeyStoreSupporter; import lombok.SneakyThrows; +import se.swedenconnect.opensaml.eidas.ext.NodeCountry; +import se.swedenconnect.opensaml.eidas.ext.SPType; +import se.swedenconnect.opensaml.eidas.ext.SPTypeEnumeration; +import se.swedenconnect.opensaml.eidas.ext.impl.NodeCountryBuilder; +import se.swedenconnect.opensaml.eidas.ext.impl.SPTypeBuilder; @ExtendWith(SpringExtension.class) @@ -53,6 +120,8 @@ class MetadataControllerTest extends ServiceProviderTestBase { + public static final String INVALID_METADATA_VERIFICATION_CERTIFICATE_NAME = "invalidMetadataVerificationCertificate"; + @MockBean MetadataService metadataService; @@ -64,8 +133,9 @@ void setupMocks() Mockito.when(configurationService.getConfiguration()).thenReturn(createConfiguration()); // Certificate must be mocked separately - X509Certificate certificate = KeyReader.readX509Certificate(MetadataControllerTest.class.getResourceAsStream("/configuration/sigCert.crt")); - Mockito.when(configurationService.getCertificate(Mockito.anyString())).thenReturn(certificate); + X509Certificate certificate = KeyReader.readX509Certificate(MetadataControllerTest.class.getResourceAsStream("/configuration/metadata-signer.cer")); + Mockito.when(configurationService.getSamlCertificate("sigCert")).thenReturn(certificate); + Mockito.when(configurationService.getCertificate("sigCert")).thenReturn(certificate); // And again Mockito.when(configurationService.getCertificateTypes()) @@ -79,12 +149,11 @@ void testMetadataTable() throws IOException HtmlPage metadataPage = login(loginPage); HtmlTableRow demoEpa = (HtmlTableRow)metadataPage.getElementById("entry-0"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa", - getSpanText(demoEpa, "entityId")); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa, "entityId")); Assertions.assertEquals("✔", getSpanText(demoEpa, "signatureValid")); HtmlTableRow demoEpaInvalid = (HtmlTableRow)metadataPage.getElementById("entry-1"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid", + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", getSpanText(demoEpaInvalid, "entityId")); Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); } @@ -100,9 +169,9 @@ void testDelete() throws IOException HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); HtmlPage metadataPage = login(loginPage); - // Click on delete for demo_epa_invalid - HtmlTableRow demoEpaInvalid = (HtmlTableRow)metadataPage.getElementById("entry-1"); - List anchors = demoEpaInvalid.getByXPath(".//a"); + // Click on delete for localhost:8445 + HtmlTableRow invalidMetadata = (HtmlTableRow)metadataPage.getElementById("entry-1"); + List anchors = invalidMetadata.getByXPath(".//a"); Assertions.assertEquals(2, anchors.size()); Assertions.assertTrue(anchors.get(1).getHrefAttribute().contains("/remove")); HtmlPage removePage = anchors.get(1).click(); @@ -111,20 +180,19 @@ void testDelete() throws IOException HtmlDivision cardBody = removePage.getFirstByXPath("//div[@class=('card-body')]"); HtmlParagraph paragraph = cardBody.getFirstByXPath(".//p"); Assertions.assertTrue(paragraph.asNormalizedText() - .contains("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid")); + .contains("https://localhost:9445/eIDASDemoApplication/Metadata")); HtmlTextArea textarea = cardBody.getFirstByXPath("//textarea"); - Assertions.assertEquals(new String(MetadataControllerTest.class.getResourceAsStream("/configuration/demo_epa_invalid.xml") + Assertions.assertEquals(new String(MetadataControllerTest.class.getResourceAsStream("/configuration/metadata-9445-invalid.xml") .readAllBytes(), StandardCharsets.UTF_8), textarea.getText()); HtmlPage afterDeletion = (HtmlPage)click(removePage, "delete"); // Check that the deletion was successful - assertMessageAlert(afterDeletion, - "Metadata file removed: https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid"); - HtmlTableRow demoEpa = (HtmlTableRow)afterDeletion.getElementById("entry-0"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa", - getSpanText(demoEpa, "entityId")); + assertMessageAlert(afterDeletion, "Metadata file removed: https://localhost:9445/eIDASDemoApplication/Metadata"); + HtmlTableRow validMetadata = (HtmlTableRow)afterDeletion.getElementById("entry-0"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", + getSpanText(validMetadata, "entityId")); Assertions.assertNull(afterDeletion.getElementById("entry-1")); } @@ -135,8 +203,8 @@ void testConnectorMetadataDownload() throws IOException HtmlPage metadataPage = login(loginPage); // Click on download for demo_epa - HtmlTableRow demoEpaInvalid = (HtmlTableRow)metadataPage.getElementById("entry-0"); - List anchors = demoEpaInvalid.getByXPath(".//a"); + HtmlTableRow validMetadata = (HtmlTableRow)metadataPage.getElementById("entry-0"); + List anchors = validMetadata.getByXPath(".//a"); Assertions.assertEquals(2, anchors.size()); Assertions.assertTrue(anchors.get(0).getHrefAttribute().contains("/download")); UnexpectedPage downloadPage = anchors.get(0).click(); @@ -146,7 +214,7 @@ void testConnectorMetadataDownload() throws IOException downloadPage.getWebResponse().getResponseHeaderValue("Content-Type")); Assertions.assertEquals("attachment; filename=Metadata.xml", downloadPage.getWebResponse().getResponseHeaderValue("Content-Disposition")); - Assertions.assertArrayEquals(ServiceProviderTestBase.class.getResourceAsStream("/configuration/demo_epa.xml") + Assertions.assertArrayEquals(ServiceProviderTestBase.class.getResourceAsStream("/configuration/metadata-9443.xml") .readAllBytes(), downloadPage.getInputStream().readAllBytes()); } @@ -158,26 +226,112 @@ void testUpload() throws IOException HtmlPage metadataPage = login(loginPage); // Upload a third file - File demoEpa20File = new File(MetadataControllerTest.class.getResource("/configuration/demo_epa_20.xml").getPath()); + File demoEpa20File = new File(MetadataControllerTest.class.getResource("/configuration/metadata-9444.xml") + .getPath()); setFileUpload(metadataPage, "metadataFile", demoEpa20File); HtmlPage afterUploadPage = submitFormById(metadataPage, "uploadMetadata"); // Check the content assertMessageAlert(afterUploadPage, "Metadata file uploaded successfully"); HtmlTableRow demoEpa = (HtmlTableRow)afterUploadPage.getElementById("entry-0"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa", - getSpanText(demoEpa, "entityId")); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa, "entityId")); Assertions.assertEquals("✔", getSpanText(demoEpa, "signatureValid")); HtmlTableRow demoEpa20 = (HtmlTableRow)afterUploadPage.getElementById("entry-1"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_20", - getSpanText(demoEpa20, "entityId")); + Assertions.assertEquals("https://localhost:9444/eIDASDemoApplication/Metadata", getSpanText(demoEpa20, "entityId")); Assertions.assertEquals("✔", getSpanText(demoEpa20, "signatureValid")); HtmlTableRow demoEpaInvalid = (HtmlTableRow)afterUploadPage.getElementById("entry-2"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid", + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", + getSpanText(demoEpaInvalid, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + } + + @ParameterizedTest + @ValueSource(strings = {"/configuration/metadata-9444-shortcrypt-ec.xml", + "/configuration/metadata-9444-shortsign-ec.xml"}) + void testUploadShortCertsEc(String metaFile) throws IOException + { + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); + HtmlPage metadataPage = login(loginPage); + + // Upload a file with short EC key + File demoEpa20File = new File(MetadataControllerTest.class.getResource(metaFile).getPath()); + setFileUpload(metadataPage, "metadataFile", demoEpa20File); + HtmlPage afterUploadPage = submitFormById(metadataPage, "uploadMetadata"); + + // Check the content + assertMessageAlert(afterUploadPage, + "Certificate is not valid for that purpose because of reason Certificate with subject CN=Wurst, OU=Autent A, O=Governikus, L=Bremen, ST=Bremen, C=DE and serial 1701967321 does not meet specified minimum EC key size of 256."); + HtmlTableRow demoEpa = (HtmlTableRow)afterUploadPage.getElementById("entry-0"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa, "entityId")); + Assertions.assertEquals("✔", getSpanText(demoEpa, "signatureValid")); + + HtmlTableRow demoEpaInvalid = (HtmlTableRow)afterUploadPage.getElementById("entry-1"); + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", + getSpanText(demoEpaInvalid, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + + // Assert no more metadata are in the HTML Table + Assertions.assertNull(afterUploadPage.getElementById("entry-2")); + } + + @ParameterizedTest + @ValueSource(strings = {"/configuration/metadata-9444-shortcrypt-rsa.xml", + "/configuration/metadata-9444-shortsign-rsa.xml"}) + void testUploadShortCertsRsa(String metaFile) throws IOException + { + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); + HtmlPage metadataPage = login(loginPage); + + // Upload a file with short RSA key + File demoEpa20File = new File(MetadataControllerTest.class.getResource(metaFile).getPath()); + setFileUpload(metadataPage, "metadataFile", demoEpa20File); + HtmlPage afterUploadPage = submitFormById(metadataPage, "uploadMetadata"); + + // Check the content + assertMessageAlert(afterUploadPage, + "Certificate is not valid for that purpose because of reason Certificate with subject CN=Wurst, OU=Autent A, O=Governikus, L=Bremen, ST=Bremen, C=DE and serial 1701967541 does not meet specified minimum RSA key size of 3072."); + HtmlTableRow demoEpa = (HtmlTableRow)afterUploadPage.getElementById("entry-0"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa, "entityId")); + Assertions.assertEquals("✔", getSpanText(demoEpa, "signatureValid")); + + HtmlTableRow demoEpaInvalid = (HtmlTableRow)afterUploadPage.getElementById("entry-1"); + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", + getSpanText(demoEpaInvalid, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + + // Assert no more metadata are in the HTML Table + Assertions.assertNull(afterUploadPage.getElementById("entry-2")); + } + + @ParameterizedTest + @ValueSource(strings = {"/configuration/metadata-9444-explicit-crypt.xml", + "/configuration/metadata-9444-explicit-sign.xml"}) + void testUploadExplicitCerts(String metaFile) throws IOException + { + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); + HtmlPage metadataPage = login(loginPage); + + // Upload a file with short RSA key + File demoEpa20File = new File(MetadataControllerTest.class.getResource(metaFile).getPath()); + setFileUpload(metadataPage, "metadataFile", demoEpa20File); + HtmlPage afterUploadPage = submitFormById(metadataPage, "uploadMetadata"); + + // Check the content + assertMessageAlert(afterUploadPage, + "Certificate is not valid for that purpose because of reason Certificate with subject CN=TEST csca-germany, OU=bsi, O=bund, C=DE and serial 1264 does not use a named curve."); + HtmlTableRow demoEpa = (HtmlTableRow)afterUploadPage.getElementById("entry-0"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa, "entityId")); + Assertions.assertEquals("✔", getSpanText(demoEpa, "signatureValid")); + + HtmlTableRow demoEpaInvalid = (HtmlTableRow)afterUploadPage.getElementById("entry-1"); + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", getSpanText(demoEpaInvalid, "entityId")); Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + + // Assert no more metadata are in the HTML Table + Assertions.assertNull(afterUploadPage.getElementById("entry-2")); } @Test @@ -189,7 +343,7 @@ void testMiddlewareMetadataDownload() throws IOException HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); HtmlPage metadataPage = login(loginPage); - // Click the link in the nav bar to download the middleware metadat + // Click the link in the nav bar to download the middleware metadata List navItems = metadataPage.getByXPath("//li[@class=('nav-item')]"); HtmlListItem downloadMetadata = navItems.stream() .filter(htmlListItem -> htmlListItem.asNormalizedText() @@ -224,7 +378,7 @@ void testChangeCertificate() throws IOException .thenReturn(configuration.get().getKeyData().getCertificate()); // And again - Mockito.when(configurationService.getCertificate(Mockito.anyString())).thenAnswer(invocation -> { + Mockito.when(configurationService.getSamlCertificate(Mockito.anyString())).thenAnswer(invocation -> { String certificateName = invocation.getArgument(0, String.class); if (certificateName.equals("jks-keystore")) { @@ -247,13 +401,343 @@ void testChangeCertificate() throws IOException Assertions.assertFalse(changedCertificatePage.asNormalizedText().contains("sigCert")); HtmlTableRow demoEpa = (HtmlTableRow)changedCertificatePage.getElementById("entry-0"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa", - getSpanText(demoEpa, "entityId")); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa, "entityId")); Assertions.assertEquals("❌", getSpanText(demoEpa, "signatureValid")); HtmlTableRow demoEpaInvalid = (HtmlTableRow)changedCertificatePage.getElementById("entry-1"); - Assertions.assertEquals("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid", + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", getSpanText(demoEpaInvalid, "entityId")); Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); } + + @Test + void testWhenChangeMetadataVerificationCertificateTooShortThenShowError() throws Exception + { + // Override Mocks from SetUp Method + EidasMiddlewareConfig configuration = createConfiguration().orElseThrow(); + // Add dummy cert to key data. + configuration.getKeyData() + .getCertificate() + .add(new CertificateType(INVALID_METADATA_VERIFICATION_CERTIFICATE_NAME, ArrayUtils.EMPTY_BYTE_ARRAY, + null, + null)); + // Override mock calls from setUp method, otherwise a configuration without the dummy certificate type will be + // returned + Mockito.when(configurationService.getConfiguration()).thenReturn(Optional.of(configuration)); + Mockito.when(configurationService.getCertificateTypes()).thenReturn(configuration.getKeyData().getCertificate()); + // Mock the call when the dummy cert key size is checked + Mockito.when(configurationService.getSamlCertificate(INVALID_METADATA_VERIFICATION_CERTIFICATE_NAME)) + .thenThrow(ConfigurationException.class); + + // Actual calls to the endpoints + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); + HtmlPage metadataPage = login(loginPage); + // Select dummy cert + setSelectValue(metadataPage, + "metadataSignatureVerificationCertificateName", + INVALID_METADATA_VERIFICATION_CERTIFICATE_NAME); + HtmlPage changedCertificatePage = submitFormById(metadataPage, "metadataSignatureVerificationCertificate"); + // Verify that the expected error message is displayed and the config is not changed + assertErrorAlert(changedCertificatePage, + "Cannot save the selected metadata verification certificate: "); + Mockito.verify(configurationService, Mockito.never()).saveConfiguration(configuration, false); + + // Verify that the metadata are still present and the signature is valid + HtmlTableRow demoEpa = (HtmlTableRow)changedCertificatePage.getElementById("entry-0"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa, "entityId")); + Assertions.assertEquals("✔", getSpanText(demoEpa, "signatureValid")); + + HtmlTableRow demoEpaInvalid = (HtmlTableRow)changedCertificatePage.getElementById("entry-1"); + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", + getSpanText(demoEpaInvalid, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + } + + @ParameterizedTest + @MethodSource("testSha1Metadata") + void testInvalidAlgorithmMetadataSignature(String signatureAlgorithm, + String digestAlgorithm, + String keyStorePath, + String alias, + @TempDir Path tempDir) + throws Exception + { + File file = cretaeEntityDescriptorWithSignatureFile(signatureAlgorithm, + digestAlgorithm, + keyStorePath, + alias, + tempDir); + + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); + HtmlPage metadataPage = login(loginPage); + + // Upload a metadata file with an invalid digest algorithm or an invalid signature algorithm + setFileUpload(metadataPage, "metadataFile", file); + HtmlPage afterUploadPage = submitFormById(metadataPage, "uploadMetadata"); + + // Check the error message + assertMessageAlert(afterUploadPage, "Invalid hash or signature algorithm"); + + // Check that the other metadata files still available + HtmlTableRow demoEpa20 = (HtmlTableRow)afterUploadPage.getElementById("entry-0"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa20, "entityId")); + Assertions.assertEquals("✔", getSpanText(demoEpa20, "signatureValid")); + + HtmlTableRow demoEpaInvalid = (HtmlTableRow)afterUploadPage.getElementById("entry-1"); + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", + getSpanText(demoEpaInvalid, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + + // Assert no more metadata are in the HTML Table + Assertions.assertNull(afterUploadPage.getElementById("entry-2")); + } + + @ParameterizedTest + @MethodSource("testSha1Metadata") + void testInvalidAlgorithmInMetadataSignatureAlreadyInConfigPresent(String signatureAlgorithm, + String digestAlgorithm, + String keyStorePath, + String alias) + throws Exception + { + ConnectorMetadataType connectorMetadataType = new ConnectorMetadataType(); + connectorMetadataType.setEntityID("InvalidDigestAlgOrSigAlg"); + String signedEntityDesriptor = getSignedEntityDescriptor(signatureAlgorithm, digestAlgorithm, keyStorePath, alias); + connectorMetadataType.setValue(signedEntityDesriptor.getBytes(StandardCharsets.UTF_8)); + configurationService.getConfiguration() + .orElseThrow() + .getEidasConfiguration() + .getConnectorMetadata() + .add(connectorMetadataType); + + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); + HtmlPage metadataPage = login(loginPage); + + // Check the error message + assertErrorAlert(metadataPage, + "Cannot parse already saved metadata with entityId InvalidDigestAlgOrSigAlg. " + + "This metadata is not usable by the middleware and must be deleted or replaced. " + + "See the log of the middleware for more details."); + // Check that the other metadata files still available + HtmlTableRow invalidMetadataSignature = (HtmlTableRow)metadataPage.getElementById("entry-0"); + Assertions.assertEquals("InvalidDigestAlgOrSigAlg", getSpanText(invalidMetadataSignature, "entityId")); + Assertions.assertEquals("❌", getSpanText(invalidMetadataSignature, "signatureValid")); + + HtmlTableRow demoEpa20 = (HtmlTableRow)metadataPage.getElementById("entry-1"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa20, "entityId")); + Assertions.assertEquals("✔", getSpanText(demoEpa20, "signatureValid")); + + HtmlTableRow demoEpaInvalid = (HtmlTableRow)metadataPage.getElementById("entry-2"); + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", + getSpanText(demoEpaInvalid, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + + // Assert no more metadata are in the HTML Table + Assertions.assertNull(metadataPage.getElementById("entry-3")); + } + + @Test + void testCurrentMetadataVerificationCertificateNotValid() throws Exception + { + EidasMiddlewareConfig configuration = configurationService.getConfiguration().orElseThrow(); + configuration.getEidasConfiguration() + .setMetadataSignatureVerificationCertificateName(INVALID_METADATA_VERIFICATION_CERTIFICATE_NAME); + + Mockito.when(configurationService.getSamlCertificate(INVALID_METADATA_VERIFICATION_CERTIFICATE_NAME)) + .thenThrow(ConfigurationException.class); + Mockito.when(configurationService.getCertificate(INVALID_METADATA_VERIFICATION_CERTIFICATE_NAME)) + .thenThrow(ConfigurationException.class); + + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/metadataConfig")); + HtmlPage metadataPage = login(loginPage); + // Check the message + assertErrorAlert(metadataPage, "The currently selected metadata verification certificate is not valid:"); + + // Check that the other metadata files still available but without a valid signature + HtmlTableRow demoEpa20 = (HtmlTableRow)metadataPage.getElementById("entry-0"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", getSpanText(demoEpa20, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpa20, "signatureValid")); + + HtmlTableRow demoEpaInvalid = (HtmlTableRow)metadataPage.getElementById("entry-1"); + Assertions.assertEquals("https://localhost:9445/eIDASDemoApplication/Metadata", + getSpanText(demoEpaInvalid, "entityId")); + Assertions.assertEquals("❌", getSpanText(demoEpaInvalid, "signatureValid")); + + // Assert no more metadata are in the HTML Table + Assertions.assertNull(metadataPage.getElementById("entry-2")); + } + + static Stream testSha1Metadata() + { + return Stream.of(Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/keys/bos-test-tctoken.saml-sign.p12", + "bos-test-tctoken.saml-sign"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/keys/bos-test-tctoken.saml-sign.p12", + "bos-test-tctoken.saml-sign"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1, + SignatureConstants.ALGO_ID_DIGEST_SHA256, + "/keys/bos-test-tctoken.saml-sign.p12", + "bos-test-tctoken.saml-sign"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/keys/ecc2.p12", + "ec_nist_p256"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA256, + SignatureConstants.ALGO_ID_DIGEST_SHA1, + "/keys/ecc2.p12", + "ec_nist_p256"), + Arguments.of(XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1, + SignatureConstants.ALGO_ID_DIGEST_SHA256, + "/keys/ecc2.p12", + "ec_nist_p256")); + } + + private File cretaeEntityDescriptorWithSignatureFile(String sigAlg, + String digestAlg, + String keyStorePath, + String alias, + Path tempDir) + throws Exception + { + String metadataAsString = getSignedEntityDescriptor(sigAlg, digestAlg, keyStorePath, alias); + + Path tempMetadaFile = tempDir.resolve("tempMetadaFile"); + Path write = Files.writeString(tempMetadaFile, metadataAsString); + + return write.toFile(); + } + + private String getSignedEntityDescriptor(String sigAlg, String digestAlg, String keyStorePath, String alias) + throws Exception + { + EidasSaml.init(); + EntityDescriptor entityDescriptor = new EntityDescriptorBuilder().buildObject(); + entityDescriptor.setEntityID("InvalidDigestAlgOrSigAlg"); + entityDescriptor.setValidUntil(Instant.now().plus(30, ChronoUnit.DAYS)); + SPSSODescriptor spssoDescriptor = new SPSSODescriptorBuilder().buildObject(); + Extensions extensions = new ExtensionsBuilder().buildObject(); + NodeCountry nc = new NodeCountryBuilder().buildObject(); + nc.setNodeCountry("SE"); + extensions.getUnknownXMLObjects().add(nc); + spssoDescriptor.setExtensions(extensions); + spssoDescriptor.setAuthnRequestsSigned(true); + spssoDescriptor.setWantAssertionsSigned(false); + spssoDescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS); + + addCerts(spssoDescriptor, configurationService.getCertificate("sigCert")); + NameIDFormat persistent = new NameIDFormatBuilder().buildObject(); + persistent.setURI(NameIDType.PERSISTENT); + spssoDescriptor.getNameIDFormats().add(persistent); + + NameIDFormat trans = new NameIDFormatBuilder().buildObject(); + trans.setURI(NameIDType.TRANSIENT); + spssoDescriptor.getNameIDFormats().add(trans); + + NameIDFormat unspecified = new NameIDFormatBuilder().buildObject(); + unspecified.setURI(NameIDType.UNSPECIFIED); + spssoDescriptor.getNameIDFormats().add(unspecified); + + AssertionConsumerService assertionConsumerService = new AssertionConsumerServiceBuilder().buildObject(); + assertionConsumerService.setBinding(SAMLConstants.SAML2_POST_BINDING_URI); + assertionConsumerService.setLocation("https://dummmy-url.de"); + assertionConsumerService.setIsDefault(true); + spssoDescriptor.getAssertionConsumerServices().add(assertionConsumerService); + extensions = new ExtensionsBuilder().buildObject(); + + SPType spType = new SPTypeBuilder().buildObject(); + spType.setType(SPTypeEnumeration.PUBLIC); + extensions.getUnknownXMLObjects().add(spType); + + DigestMethod digestMethod = new DigestMethodBuilder().buildObject(); + digestMethod.setAlgorithm(MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256); + extensions.getUnknownXMLObjects().add(digestMethod); + + SigningMethod signingMethodRSA = new SigningMethodBuilder().buildObject(); + signingMethodRSA.setAlgorithm(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1); + signingMethodRSA.setMinKeySize(3072); + signingMethodRSA.setMaxKeySize(4096); + extensions.getUnknownXMLObjects().add(signingMethodRSA); + + entityDescriptor.getRoleDescriptors().add(spssoDescriptor); + addSignature(entityDescriptor, digestAlg, sigAlg, keyStorePath, alias); + return marshallMetadata(entityDescriptor); + } + + private void addSignature(EntityDescriptor entityDescriptor, + String digestAlg, + String sigAlg, + String keyStorePath, + String alias) + throws Exception + { + Signature signature = new SignatureBuilder().buildObject(); + File keystoreFile = new File(MetadataControllerTest.class.getResource(keyStorePath).toURI()); + KeyStore keyStore = KeyStoreSupporter.readKeyStore(keystoreFile, "123456"); + PrivateKey privateKey = (PrivateKey)keyStore.getKey(alias, "123456".toCharArray()); + X509Certificate certificate = (X509Certificate)keyStore.getCertificate(alias); + BasicX509Credential credential = new BasicX509Credential(certificate, privateKey); + signature.setSigningCredential(credential); + signature.setSignatureAlgorithm(sigAlg); + signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); + org.opensaml.xmlsec.signature.X509Certificate x509CertificateSignature = new X509CertificateBuilder().buildObject(); + x509CertificateSignature.setValue(Base64.getEncoder().encodeToString(certificate.getEncoded())); + X509Data x509DataSignature = new X509DataBuilder().buildObject(); + x509DataSignature.getX509Certificates().add(x509CertificateSignature); + KeyInfo keyInfoSignature = new KeyInfoBuilder().buildObject(); + keyInfoSignature.getX509Datas().add(x509DataSignature); + signature.setKeyInfo(keyInfoSignature); + entityDescriptor.setSignature(signature); + ((SAMLObjectContentReference)signature.getContentReferences().get(0)).setDigestAlgorithm(digestAlg); + } + + private void addCerts(SPSSODescriptor spssoDescriptor, X509Certificate cert) throws Exception + { + KeyDescriptor keyDescriptorSigning = new KeyDescriptorBuilder().buildObject(); + keyDescriptorSigning.setUse(UsageType.SIGNING); + org.opensaml.xmlsec.signature.X509Certificate x509CertificateSigning = new X509CertificateBuilder().buildObject(); + x509CertificateSigning.setValue(Base64.getEncoder().encodeToString(cert.getEncoded())); + X509Data x509DataSigning = new X509DataBuilder().buildObject(); + x509DataSigning.getX509Certificates().add(x509CertificateSigning); + KeyInfo keyInfoSigning = new KeyInfoBuilder().buildObject(); + keyInfoSigning.getX509Datas().add(x509DataSigning); + keyDescriptorSigning.setKeyInfo(keyInfoSigning); + spssoDescriptor.getKeyDescriptors().add(keyDescriptorSigning); + + KeyDescriptor keyDescriptorEncryption = new KeyDescriptorBuilder().buildObject(); + keyDescriptorEncryption.setUse(UsageType.ENCRYPTION); + org.opensaml.xmlsec.signature.X509Certificate x509CertificateEncryption = new X509CertificateBuilder().buildObject(); + x509CertificateEncryption.setValue(Base64.getEncoder().encodeToString(cert.getEncoded())); + X509Data x509DataEncryption = new X509DataBuilder().buildObject(); + x509DataEncryption.getX509Certificates().add(x509CertificateEncryption); + KeyInfo keyInfoEncryption = new KeyInfoBuilder().buildObject(); + keyInfoEncryption.getX509Datas().add(x509DataEncryption); + keyDescriptorEncryption.setKeyInfo(keyInfoEncryption); + + EncryptionMethod encryptionMethod = new EncryptionMethodBuilder().buildObject(); + encryptionMethod.setAlgorithm(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM); + keyDescriptorEncryption.getEncryptionMethods().add(encryptionMethod); + encryptionMethod = new EncryptionMethodBuilder().buildObject(); + encryptionMethod.setAlgorithm(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM); + keyDescriptorEncryption.getEncryptionMethods().add(encryptionMethod); + spssoDescriptor.getKeyDescriptors().add(keyDescriptorEncryption); + } + + private String marshallMetadata(EntityDescriptor entityDescriptor) throws Exception + { + EntityDescriptorMarshaller marshaller = new EntityDescriptorMarshaller(); + Element all = null; + all = marshaller.marshall(entityDescriptor); + Signer.signObject(entityDescriptor.getSignature()); + + try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) + { + Transformer transformer = Utils.getTransformer(); + transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.displayName()); + transformer.transform(new DOMSource(all), new StreamResult(stream)); + return stream.toString(StandardCharsets.UTF_8); + } + } } diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/OverviewControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/OverviewControllerTest.java index f8270b8f..ef967377 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/OverviewControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/OverviewControllerTest.java @@ -50,7 +50,7 @@ void noServiceProviders() throws IOException private HtmlPage openDashboard() throws IOException { - HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/")); + HtmlPage loginPage = getWebClient().getPage(getRequestUrl("/dashboard")); HtmlPage dashboardPage = login(loginPage); Assertions.assertTrue(dashboardPage.getUrl().getPath().endsWith("/dashboard")); return dashboardPage; diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderControllerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderControllerTest.java index c15f5061..42eef65b 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderControllerTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderControllerTest.java @@ -78,7 +78,7 @@ class ServiceProviderControllerTest extends WebAdminTestBase public static final String ALERT_MSG_HTML_ID = "alertMSG"; - private static final String NAME_HTML_ID = "Name"; + private static final String NAME_HTML_ID = "name"; private static final String ENABLED_HTML_ID = "Active"; @@ -153,8 +153,6 @@ void testCreateServiceproviderWithWrongValues() throws IOException assertValidationMessagePresent(createServiceproviderConfigPage, DVCA_CONFIGURATION_HTML_ID, THIS_DVCA_CONFIG_DOES_NOT_EXIST); - assertValidationMessagePresent(createServiceproviderConfigPage, CLIENT_KEYPAIR_NAME_HTML_ID, HAS_TO_BE_SELECTED); - assertTrue(configurationService.getConfiguration() .map(EidasMiddlewareConfig::getEidConfiguration) diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderTestBase.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderTestBase.java index d0d738e4..86632e4e 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderTestBase.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/ServiceProviderTestBase.java @@ -142,19 +142,19 @@ protected Optional createConfiguration() // Add connector metadata and a validation certificate EidasMiddlewareConfig.EidasConfiguration eidasConfiguration = new EidasMiddlewareConfig.EidasConfiguration(); ConnectorMetadataType validMetadata = new ConnectorMetadataType(); - validMetadata.setValue(ServiceProviderTestBase.class.getResourceAsStream("/configuration/demo_epa.xml") + validMetadata.setValue(ServiceProviderTestBase.class.getResourceAsStream("/configuration/metadata-9443.xml") .readAllBytes()); - validMetadata.setEntityID("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa"); + validMetadata.setEntityID("https://localhost:9443/eIDASDemoApplication/Metadata"); eidasConfiguration.getConnectorMetadata().add(validMetadata); ConnectorMetadataType invalidMetadata = new ConnectorMetadataType(); - invalidMetadata.setValue(ServiceProviderTestBase.class.getResourceAsStream("/configuration/demo_epa_invalid.xml") + invalidMetadata.setValue(ServiceProviderTestBase.class.getResourceAsStream("/configuration/metadata-9445-invalid.xml") .readAllBytes()); - invalidMetadata.setEntityID("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid"); + invalidMetadata.setEntityID("https://localhost:9445/eIDASDemoApplication/Metadata"); eidasConfiguration.getConnectorMetadata().add(invalidMetadata); eidasConfiguration.setMetadataSignatureVerificationCertificateName("sigCert"); keyData.getCertificate() .add(new CertificateType("sigCert", - ServiceProviderTestBase.class.getResourceAsStream("/configuration/sigCert.crt") + ServiceProviderTestBase.class.getResourceAsStream("/configuration/metadata-signer.cer") .readAllBytes(), null, null)); eidasMiddlewareConfig.setEidasConfiguration(eidasConfiguration); diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/base/WebAdminTestBase.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/base/WebAdminTestBase.java index c6431dc7..2c4bc005 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/config/base/WebAdminTestBase.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/config/base/WebAdminTestBase.java @@ -22,7 +22,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterEach; diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataCheckerTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataCheckerTest.java new file mode 100644 index 00000000..f959cd87 --- /dev/null +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/eidserver/eac/EACSignedDataCheckerTest.java @@ -0,0 +1,83 @@ +package de.governikus.eumw.poseidas.eidserver.eac; + +import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.ByteArrayInputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.boot.test.context.SpringBootTest; + +import de.governikus.eumw.poseidas.SpringApplicationContextHelper; +import de.governikus.eumw.poseidas.cardbase.Hex; +import de.governikus.eumw.poseidas.eidserver.crl.CertificationRevocationListImpl; +import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationService; +import de.governikus.eumw.poseidas.server.idprovider.config.ConfigurationTestHelper; +import de.governikus.eumw.utils.key.SecurityProvider; + + +@SpringBootTest +class EACSignedDataCheckerTest +{ + + private static CertificateFactory cf; + + @BeforeAll + static void init() throws CertificateException + { + cf = CertificateFactory.getInstance("X509", SecurityProvider.BOUNCY_CASTLE_PROVIDER); + } + + @BeforeEach + void initSingle() throws Exception + { + ConfigurationService cs = SpringApplicationContextHelper.getConfigurationService(); + cs.saveConfiguration(ConfigurationTestHelper.createValidConfiguration(), false); + X509Certificate masterListTrustAnchor = (X509Certificate)cf.generateCertificate(ConfigurationTestHelper.class.getResourceAsStream("/TEST_csca_germany.cer")); + if (!CertificationRevocationListImpl.isInitialized()) + { + CertificationRevocationListImpl.initialize(Set.of(masterListTrustAnchor), cs); + } + } + + @Test + void testSuccess() throws Exception + { + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(Base64.getDecoder() + .decode("MIIEsjCCBBagAwIBAgICBPUwCgYIKoZIzj0EAwQwRjELMAkGA1UEBhMCREUxDTALBgNVBAoMBGJ1bmQxDDAKBgNVBAsMA2JzaTEaMBgGA1UEAwwRVEVTVCBjc2NhLWdlcm1hbnkwHhcNMjExMDA3MDc1OTAyWhcNMzIwNTA3MjM1OTU5WjBtMQswCQYDVQQGEwJERTEdMBsGA1UECgwUQnVuZGVzZHJ1Y2tlcmVpIEdtYkgxDTALBgNVBAUTBDAxMDgxMDAuBgNVBAMMJ1RFU1QgRG9jdW1lbnQgU2lnbmVyIElkZW50aXR5IERvY3VtZW50czCCAbUwggFNBgcqhkjOPQIBMIIBQAIBATA8BgcqhkjOPQEBAjEAjLkegqM4bSgPXW9+UOZB3xUvcQntVFa0ErHaGX+3ESOs06cpkB0acYdHABMxB+xTMGQEMHvDgsY9jBUMPHIICs4Fr6DCvqKOT7InhxORZe+6kfkPiqWBSlA61OsEqMfdIs4oJgQwBKjH3SLOKCaLObVUFvBEfC+3feEH3NKmLogOpT7rYtV8tDkCldvJlDq3hpb6UEwRBGEEHRxk8GjPRf+ipjqBt8E/a4hHo+d+8U/j23/K/gy9EOjoJuA0NtZGqu+HsuJH1K8eir4ddSD5wqRcseuOlc/VUmK3Cyn+7Fhk4ZwFT/mRKSgORkYhd5GBEUKCA0EmPFMVAjEAjLkegqM4bSgPXW9+UOZB3xUvcQntVFazHxZubKwEJafPOrava3/DEDuIMgLpBGVlAgEBA2IABA3N5BZnRi1wEtqHk/GO2DNrmKrYUQDcfDi9eYOR2MZhjEZ+KK/guADIggcu4vSDTij7flVLDT1WpenMMqtf9/j7Dg3yOA8aQQgdaw3aQIMSfC1xL+FndSUj9E1Ruqz83aOCAW0wggFpMB8GA1UdIwQYMBaAFOT5NO5e2Y1hw/LvGknykIAdCPu5MB0GA1UdDgQWBBSbh4oRjoNVXrDg80r8v+R80HxhdjAOBgNVHQ8BAf8EBAMCB4AwKwYDVR0QBCQwIoAPMjAyMTEwMDcwNzU5MDJagQ8yMDIyMDUwNzIzNTk1OVowFgYDVR0gBA8wDTALBgkEAH8ABwMBAQEwLQYDVR0RBCYwJIISYnVuZGVzZHJ1Y2tlcmVpLmRlpA4wDDEKMAgGA1UEBwwBRDBRBgNVHRIESjBIgRhjc2NhLWdlcm1hbnlAYnNpLmJ1bmQuZGWGHGh0dHBzOi8vd3d3LmJzaS5idW5kLmRlL2NzY2GkDjAMMQowCAYDVQQHDAFEMBkGB2eBCAEBBgIEDjAMAgEAMQcTAUETAklEMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly93d3cuYnNpLmJ1bmQuZGUvdGVzdF9jc2NhX2NybDAKBggqhkjOPQQDBAOBiQAwgYUCQQChTWxsAhIRE67KiQNC5jjwZtw1rGhs6CQLQmY1bwFPLvwDJ2dfanshiE3lUYTiElWa7EIYTIQn9GK0eIOOFATLAkAWHop5XlG3wYicX8xqoGUac/348uQrwoRuAd9nELw+zNFX3XreASe4cTUubYpyPZ5m/Yej6MHxoaf1H5clp+/X"))); + EACSignedDataChecker checker = new EACSignedDataChecker(List.of(cert), ""); + assertNotNull(checker.checkSignedData(Hex.parse("308208ee06092a864886f70d010702a08208df308208db020103310f300d06096086480165030402020500308202cd060804007f0007030201a08202bf048202bb318202b7300d060804007f00070202020201023012060a04007f000702020302020201020201413012060a04007f0007020203020202010302014a3012060a04007f0007020204020202010202010d3012060a04007f0007020204060202010202010d3017060a04007f0007020205020330090201010201430101ff3017060a04007f0007020205020330090201010201440101003019060904007f000702020502300c060704007f0007010202010d301b060b04007f000702020b010203300902010102010002010102014a301c060904007f000702020302300c060704007f0007010202010d020141301c060904007f000702020302300c060704007f0007010202010d02014a302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c3062060904007f0007020201023052300c060704007f0007010202010d034200042a5500dcd0884c60ba95bb583e28500f95c9ac67f0cda44f3c53c4255ec6d75a096534a345e78b3b8d69afd6fff0c9934531e72f8b76ad75b1aa58020afc5c3d02010d3062060904007f0007020201023052300c060704007f0007010202010d03420004326fef66d0f1691ff70f971fca96c4577f9e924531c3e793f76ee8c1de5b44674f2246994411a86e746e5545a35c5116737cd2aaa60eec5a7b166ab89575a02c0201413081bb060a04007f000702020103023081a73081a4305e060904007f0007010102033051300c060704007f0007010202010d0441045f5cb7d0ac1d1e0852b409914f9a5d74bef88213ddf341d05fd091c37c7c8e454b94fc146c8c56cbd695d45f8c2c21bd166b07d5febdc9db3c0fdbc0876af128034200045f5cb7d0ac1d1e0852b409914f9a5d74bef88213ddf341d05fd091c37c7c8e454b94fc146c8c56cbd695d45f8c2c21bd166b07d5febdc9db3c0fdbc0876af128300382014aa08204b6308204b230820416a003020102020204f5300a06082a8648ce3d0403043046310b3009060355040613024445310d300b060355040a0c0462756e64310c300a060355040b0c03627369311a301806035504030c115445535420637363612d6765726d616e79301e170d3231313030373037353930325a170d3332303530373233353935395a306d310b3009060355040613024445311d301b060355040a0c1442756e646573647275636b6572656920476d6248310d300b06035504051304303130383130302e06035504030c275445535420446f63756d656e74205369676e6572204964656e7469747920446f63756d656e7473308201b53082014d06072a8648ce3d020130820140020101303c06072a8648ce3d01010231008cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a71874700133107ec53306404307bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd22ce2826043004a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696fa504c110461041d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e247d4af1e8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341263c53150231008cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046565020101036200040dcde41667462d7012da8793f18ed8336b98aad85100dc7c38bd798391d8c6618c467e28afe0b800c882072ee2f4834e28fb7e554b0d3d56a5e9cc32ab5ff7f8fb0e0df2380f1a41081d6b0dda4083127c2d712fe167752523f44d51baacfcdda382016d30820169301f0603551d23041830168014e4f934ee5ed98d61c3f2ef1a49f290801d08fbb9301d0603551d0e041604149b878a118e83555eb0e0f34afcbfe47cd07c6176300e0603551d0f0101ff040403020780302b0603551d1004243022800f32303231313030373037353930325a810f32303232303530373233353935395a30160603551d20040f300d300b060904007f000703010101302d0603551d1104263024821262756e646573647275636b657265692e6465a40e300c310a300806035504070c014430510603551d12044a30488118637363612d6765726d616e79406273692e62756e642e6465861c68747470733a2f2f7777772e6273692e62756e642e64652f63736361a40e300c310a300806035504070c01443019060767810801010602040e300c02010031071301411302494430350603551d1f042e302c302aa028a0268624687474703a2f2f7777772e6273692e62756e642e64652f746573745f637363615f63726c300a06082a8648ce3d04030403818900308185024100a14d6c6c02121113aeca890342e638f066dc35ac686ce8240b4266356f014f2efc0327675f6a7b21884de55184e212559aec42184c8427f462b478838e1404cb0240161e8a795e51b7c1889c5fcc6aa0651a73fdf8f2e42bc2846e01df6710bc3eccd157dd7ade0127b871352e6d8a723d9e66fd87a3e8c1f1a1a7f51f9725a7efd73182013830820134020101304c3046310b3009060355040613024445310d300b060355040a0c0462756e64310c300a060355040b0c03627369311a301806035504030c115445535420637363612d6765726d616e79020204f5300d06096086480165030402020500a05a301706092a864886f70d010903310a060804007f0007030201303f06092a864886f70d01090431320430982db68e9a226fb6a5ec7fe2cb30cfbf0343c80807a07c921ce62fe8297d3b9b1e9f8662fe9c13228a270e3644d785b5300c06082a8648ce3d0403030500046630640230156d2947525371c7eba7aa63a54a0c9f72a59a390f6ff2db9bfd21b1f8430531770d44b7b49ed5a5723e4cb7ccc3e1080230168d2f8efbe8942b18baf0c5474159204d881ad0ca1ea89c312556dd8fe9a17af5d0ffb7147279d3935737afe909ec0ea100"))); + } + + @ParameterizedTest + @MethodSource("parameterSource") + void testFailure(String certString, String cardSecurity) throws Exception + { + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(Base64.getDecoder() + .decode(certString))); + EACSignedDataChecker checker = new EACSignedDataChecker(List.of(cert), ""); + assertNull(checker.checkSignedData(Hex.parse(cardSecurity))); + } + + private static Stream parameterSource() + { + return Stream.of(// not brainpool + Arguments.of("MIIBHjCBxaADAgECAgYBjBFo674wCgYIKoZIzj0EAwIwFjEUMBIGA1UEAwwLV3Vyc3RJc3N1ZXIwHhcNMjMxMTI3MTUzMjE3WhcNMzIwMzI3MTUzMjE3WjAXMRUwEwYDVQQDDAxXdXJzdFN1YmplY3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR7I1u28N2p9bjeWypzSYB3SZgsBmBsHTL9NnZB3jxPHAFuZkcXu/dR1WEs6zWAjDBnwceWK95Hxpgb0ZHHRoKhMAoGCCqGSM49BAMCA0gAMEUCIQCbOIVAVTJrgtq1QSqeYnQrGNuvUUfcZarjVwbAAwX5nQIgL3UadhoHwCW+aBnIa79sGvTbnyazBcg/cieqYJ0IJ7Q=", + "3082065206092a864886f70d010702a08206433082063f020103310d300b0609608648016503040201308203e0060804007f0007030201a08203d2048203ce318203ca3012060a04007f0007020204020202010202010d300d060804007f00070202020201023017060a04007f0007020205020330090201010201010101003021060904007f000702020502301406072a8648ce3d020106092b24030302080101073017060a04007f0007020205020330090201010201020101ff3012060a04007f00070202030202020102020129301c060904007f000702020302300c060704007f0007010202010d0201293062060904007f0007020201023052300c060704007f0007010202010d0342000419d4b7447788b0e1993db35500999627e739a4e5e35f02d8fb07d6122e76567f17758d7a3aa6943ef23e5e2909b3e8b31bfaa4544c2cbf1fb487f31ff239c8f80201293081a3060804007f00070202083181963012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d3062060904007f0007020201023052300c060704007f0007010202010d034200041ac6cae884a6c2b8461404150f54cd1150b21e862a4e5f21ce34290c741104bd1bf31ed91e085d7c630e8b4d10a8ae22bbb2898b44b52ea0f4cdadcf57cfba2502012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c308201e6060804007f0007020207308201d8300b0609608648016503040204308201c73021020101041c2ff0247f59dd3c646e314f03abb33ee91a586577ebdf48d3864ec34d3021020102041c37823963b71af0bf5698d1fdc30da2b7f9ece57cfa4959bee9d6d9943021020103041ce8b2a171dc1290a765f124aafe33061c08c918a1069dff5caf4c62b53021020104041cad81d20dbd4f5687fdb05e5037ec267609fde28c6036fdbdf2c8b4333021020105041ca90f28eb7a0fa0de83abf3293d14e0838b9c85fc7277cbb97737a32b3021020106041c712b8550e49a13c64dced4457e9a0f5a85dc26cd6a321596723005d63021020107041c42a8fa36b60887ed022cd3b6ecc255220fbe8cb3f607e416601fcaa63021020108041c6446e0a909967462b5c1117634f8a1b557ef74be3f606c1e94efae433021020109041c635d1017f4abc656b9fdddd7e0fbb1e992b7686e89485e6ab51b638b302102010d041c04db93544a64bc1245b10aab266386f08f8e89f72e1db178c172624d3021020111041caadee20557d41ab9969e962282caf25904475148d329d2f6b2f43e343021020112041c57ce396ca707b96fa37c580f693230e4d4aebb97293f0909489d95cb302102010a041c1880a259cdb497c15a7fdd1c9ac9490d7dc0d18743378603d43d1d4fa08201223082011e3081c5a0030201020206018c1168ebbe300a06082a8648ce3d04030230163114301206035504030c0b5775727374497373756572301e170d3233313132373135333231375a170d3332303332373135333231375a30173115301306035504030c0c57757273745375626a6563743059301306072a8648ce3d020106082a8648ce3d030107034200047b235bb6f0dda9f5b8de5b2a7349807749982c06606c1d32fd367641de3c4f1c016e664717bbf751d5612ceb35808c3067c1c7962bde47c6981bd191c74682a1300a06082a8648ce3d04030203480030450221009b38854055326b82dab5412a9e62742b18dbaf5147dc65aae35706c00305f99d02202f751a761a07c025be6819c86bbf6c1af4db9f26b305c83f7227aa609d0827b43182011f3082011b020101302030163114301206035504030c0b57757273744973737565720206018c1168ebbe300b0609608648016503040201a08192301706092a864886f70d010903310a060804007f0007030201301c06092a864886f70d010905310f170d3233313132373135333231385a302806092a864886f70d010934311b3019300b0609608648016503040201a10a06082a8648ce3d040302302f06092a864886f70d0109043122042009ab7f4ecd22f7b164acec325af673964d93d1457a57a50206b63ea738711f69300a06082a8648ce3d040302044630440220082d92cb14714776a89ebb7ad9988a57867dedd5ea418f6c9e85ac8e32b819e002205dfcf4ade996a077fbfd75f0f97dcce09b6ee336506334de9eb11fadafb313fa"), + // RSA (unsupported sigalg) + Arguments.of("MIIEqzCCApOgAwIBAgIGAYwRe63wMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC1d1cnN0SXNzdWVyMB4XDTIzMTEyNzE1NTI0N1oXDTMyMDMyNzE1NTI0N1owFzEVMBMGA1UEAwwMV3Vyc3RTdWJqZWN0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjnXM8LOnNPJq5Z8G4Vv7mFX1wEfWi9shzLffTryPVf5axT5tZCNXD2VYTA7TFNfOsP3r/M6NEB8mtuyOV5f1f8tERSkjrIc7fdSTF54/khqNoahczCEV7fOR+b0uqR6x6qzA5k3QREwFVEcvqJB6D0SEeK3CH5TWNIloer10rQhbDLGbn1NLTpaHk9WR6ENeBM9i5xWKyYe6vZDq9UIDIcSZhltr8Ril/crV7iqtG4K9Fz1mIfHHLF5LrrRf1CdsRoDbHqQ21sXMsGY+gKECXX4bx2vsJDT8ld/iQxvFo/+Z+Byof/moCQsBDHS+RKRnysAns7bd8fVYTpS90D1uCUOH6BMokN/KsDVojH7weeaqSdQZuuj1VRhoXwFC1NsnpISvv/Ryu48geo9aoyf6pQipMAAOp6jeM+AhPOvVNoRM6P52HcWlGbLorellmfWFcr0ugHI5KCJYZx2rmju/ywypw4EsvyTPehgwJRNF3gVAGsueHfWEHXLLr50cWSkryz9TL9hlZrl70R8Bx2oKtKWTUZT7Z/Q+cTjSoW2BctVlKQYdm3al/5jvuREq815R4bvhPD2JTP+416AkaqWEUTxDdJYo5D5DH1CiHUqE2MHWitGiDUhmQE3cjqpOuBZLw3AiizLcNte3756fZkkSiXhR/qpnaXpRb3LMUmm1z/0CAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAJfWW66mFSiobk8PDimu84pAi5ao0Xi9pyZXQaKNPN9Eq3mi5AUJjl8hOS58L5zfIZ54NmzdA1AD1z/t2z2yD66fszxaHRU/5EKjl1EpbGRDgPrYgtJas1d8O8ohQ96EbXY6X7o3BrACf2BHCbgzF1fcovRbS9ngo0hQqmQz49loWDIwqgJSrTZNjk8mo3KP4UrndoxgytNsYp6RtgtOLhTjRHksGGbhDYgpxxIG26CQDPiYYGLqn8xI7FuGPFw3+219FaCaUZH2lKK8+U06dsdL4a8w/9j6flZEruGvKHwJpmzx75jkjqAkgkK+GjGU5zN0eCx1UQJ5sRtlWf0FnXmLcz8yiSdVV3TjmjSzVXWCnpz27rS41h6r0ELJKkVy3h9RknESR2FG0rM6478EhHIuRzcc01CBOupr63OEzzQYS2Of7NqMW+QaplUI1syu08GrLrfyRZNRclG71w9yEaLXtxGlVOdjrG+unbjTfAIXrPqp6xpaKa1Vx0cVTwFi5iMt71oRF61VMYe0OugIIwKYqNXV3uAnRUugSipg0NxV9lSLZW/krRJ6gzAlbUD7ETeW5JuO0y0euYWtLGUqam5LMZ2xT7stJhRiVf+HcLigIzUpeYNvv25UwRSH4qMmL5KbCuiCg0hH2o69NtMq+AjDVPDVoVxi6uJPiloarANs=", + "30820ba106092a864886f70d010702a0820b9230820b8e020103310d300b0609608648016503040201308203e0060804007f0007030201a08203d2048203ce318203ca3012060a04007f0007020204020202010202010d300d060804007f00070202020201023017060a04007f0007020205020330090201010201010101003021060904007f000702020502301406072a8648ce3d020106092b24030302080101073017060a04007f0007020205020330090201010201020101ff3012060a04007f00070202030202020102020129301c060904007f000702020302300c060704007f0007010202010d0201293062060904007f0007020201023052300c060704007f0007010202010d0342000419d4b7447788b0e1993db35500999627e739a4e5e35f02d8fb07d6122e76567f17758d7a3aa6943ef23e5e2909b3e8b31bfaa4544c2cbf1fb487f31ff239c8f80201293081a3060804007f00070202083181963012060a04007f0007020203020202010202012d301c060904007f000702020302300c060704007f0007010202010d02012d3062060904007f0007020201023052300c060704007f0007010202010d034200041ac6cae884a6c2b8461404150f54cd1150b21e862a4e5f21ce34290c741104bd1bf31ed91e085d7c630e8b4d10a8ae22bbb2898b44b52ea0f4cdadcf57cfba2502012d302a060804007f0007020206161e687474703a2f2f6273692e62756e642e64652f6369662f6e70612e786d6c308201e6060804007f0007020207308201d8300b0609608648016503040204308201c73021020101041c2ff0247f59dd3c646e314f03abb33ee91a586577ebdf48d3864ec34d3021020102041c37823963b71af0bf5698d1fdc30da2b7f9ece57cfa4959bee9d6d9943021020103041ce8b2a171dc1290a765f124aafe33061c08c918a1069dff5caf4c62b53021020104041cad81d20dbd4f5687fdb05e5037ec267609fde28c6036fdbdf2c8b4333021020105041ca90f28eb7a0fa0de83abf3293d14e0838b9c85fc7277cbb97737a32b3021020106041c712b8550e49a13c64dced4457e9a0f5a85dc26cd6a321596723005d63021020107041c42a8fa36b60887ed022cd3b6ecc255220fbe8cb3f607e416601fcaa63021020108041c6446e0a909967462b5c1117634f8a1b557ef74be3f606c1e94efae433021020109041c635d1017f4abc656b9fdddd7e0fbb1e992b7686e89485e6ab51b638b302102010d041c04db93544a64bc1245b10aab266386f08f8e89f72e1db178c172624d3021020111041caadee20557d41ab9969e962282caf25904475148d329d2f6b2f43e343021020112041c57ce396ca707b96fa37c580f693230e4d4aebb97293f0909489d95cb302102010a041c1880a259cdb497c15a7fdd1c9ac9490d7dc0d18743378603d43d1d4fa08204af308204ab30820293a0030201020206018c117badf0300d06092a864886f70d01010b050030163114301206035504030c0b5775727374497373756572301e170d3233313132373135353234375a170d3332303332373135353234375a30173115301306035504030c0c57757273745375626a65637430820222300d06092a864886f70d01010105000382020f003082020a02820201008e75ccf0b3a734f26ae59f06e15bfb9855f5c047d68bdb21ccb7df4ebc8f55fe5ac53e6d6423570f65584c0ed314d7ceb0fdebfcce8d101f26b6ec8e5797f57fcb44452923ac873b7dd493179e3f921a8da1a85ccc2115edf391f9bd2ea91eb1eaacc0e64dd0444c0554472fa8907a0f448478adc21f94d63489687abd74ad085b0cb19b9f534b4e968793d591e8435e04cf62e7158ac987babd90eaf5420321c499865b6bf118a5fdcad5ee2aad1b82bd173d6621f1c72c5e4baeb45fd4276c4680db1ea436d6c5ccb0663e80a1025d7e1bc76bec2434fc95dfe2431bc5a3ff99f81ca87ff9a8090b010c74be44a467cac027b3b6ddf1f5584e94bdd03d6e094387e8132890dfcab035688c7ef079e6aa49d419bae8f55518685f0142d4db27a484afbff472bb8f207a8f5aa327faa508a930000ea7a8de33e0213cebd536844ce8fe761dc5a519b2e8ade96599f58572bd2e807239282258671dab9a3bbfcb0ca9c3812cbf24cf7a1830251345de05401acb9e1df5841d72cbaf9d1c59292bcb3f532fd86566b97bd11f01c76a0ab4a5935194fb67f43e7138d2a16d8172d56529061d9b76a5ff98efb9112af35e51e1bbe13c3d894cffb8d7a0246aa584513c43749628e43e431f50a21d4a84d8c1d68ad1a20d4866404ddc8eaa4eb8164bc370228b32dc36d7b7ef9e9f664912897851feaa67697a516f72cc5269b5cffd0203010001300d06092a864886f70d01010b0500038202010025f596eba9854a2a1b93c3c38a6bbce29022e5aa345e2f69c995d068a34f37d12ade68b901426397c84e4b9f0be737c8679e0d9b3740d400f5cffb76cf6c83eba7eccf1687454ff910a8e5d44a5b1910e03eb620b496acd5df0ef28850f7a11b5d8e97ee8dc1ac009fd811c26e0cc5d5f728bd16d2f67828d2142a990cf8f65a160c8c2a8094ab4d936393c9a8dca3f852b9dda31832b4db18a7a46d82d38b8538d11e4b0619b843620a71c481b6e824033e261818baa7f3123b16e18f170dfedb5f45682694647da528af3e534e9db1d2f86bcc3ff63e9f95912bb86bca1f02699b3c7be63923a8092090af868c6539ccdd1e0b1d54409e6c46d9567f41675e62dccfcca249d555dd38e68d2cd55d60a7a73dbbad2e3587aaf410b24a915cb787d4649c4491d851b4acceb8efc1211c8b91cdc734d4204eba9afadce133cd0612d8e7fb36a316f906a9954235b32bb4f06acbadfc9164d45c946ef5c3dc8468b5edc4695539d8eb1beba76e34df0085eb3eaa7ac6968a6b5571d1c553c058b988cb7bd68445eb554c61ed0eba0208c0a62a357577b809d152e8128a983437157d9522d95bf92b449ea0cc095b503ec44de5b926e3b4cb47ae616b4b194a9a9b92cc676c53eecb498518957fe1dc2e2808cd4a5e60dbefdb95304521f8a8c98be4a6c2ba20a0d211f6a3af4db4cabe0230d53c35685718bab893e29686ab00db318202e1308202dd020101302030163114301206035504030c0b57757273744973737565720206018c117badf0300b0609608648016503040201a08195301706092a864886f70d010903310a060804007f0007030201301c06092a864886f70d010905310f170d3233313132373135353234375a302b06092a864886f70d010934311e301c300b0609608648016503040201a10d06092a864886f70d01010b0500302f06092a864886f70d0109043122042009ab7f4ecd22f7b164acec325af673964d93d1457a57a50206b63ea738711f69300d06092a864886f70d01010b0500048202001ec9076614c983b290698920df8809f8e381038592a3e0bdbec92aca62eb5f43b3ced54a768b534912db54b9e8453f986ea878abf4b4352e73082a36f9db3328cb78bd9976bfc35324143456a5aac3eced5e8e8c57ee305ce654b3f3e68b01533a1d3a0cd8d4e4997de8bcf083f540027bd847027d3a8a6d678364cdc9f6031404803483022b8993856d84f14946983c0c5f89cff275542b5f67ce4451f10297c4c998f1aa89aab1ce8466f049e992545e218b372e1c4535ae11f2c66cc679b5fe4324b79eb554bdf181cc8da94decd5e543309916c4456c5bb09acc02a2d07f68422a209fa5f790ff0655d837bb9e7275689465d3418a098577d55a80c59d852a77feabf5139f4125f6497a20c5b65d6fe3b729880144f3d672cb0e51094cd4e54119c7905d01ed5e20ccdd27af5d3cfad74dbb2148e37a5c93d4e3614fb417b4743124243b8362a84621f29d4bab5113587f419fb9408ba8a623f19b1ec45b02f538791d3d89779172774f19b309b1bfbb246d2c7ceb9836397c6a2e68f3ae4e31eead91e316ece3b55dfd6139fd5354fa77108f82ba40f4acf543c68b3d57d9e160325ff657bf34432dd4136ceaa4b0c94736ce2500f01300cd8029aaba0deb7fad8ecdcc9388a409926a1b001abffda5af912931f44535865aa97e31960b22bb8973f782bc4db23a891c7b39b441b6e58cd4f9160956c4c57765a37d102b")); + } +} diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationServiceTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationServiceTest.java index 9ffe4c0e..4ce0cbd4 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationServiceTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/server/idprovider/config/ConfigurationServiceTest.java @@ -9,13 +9,20 @@ package de.governikus.eumw.poseidas.server.idprovider.config; +import java.math.BigInteger; import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; import java.util.Optional; +import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; @@ -27,6 +34,8 @@ import de.governikus.eumw.config.KeyStoreType; import de.governikus.eumw.config.KeyStoreTypeType; import de.governikus.eumw.config.ServiceProviderType; +import de.governikus.eumw.eidascommon.ErrorCodeException; +import de.governikus.eumw.eidasmiddleware.eid.RequestingServiceProvider; import de.governikus.eumw.utils.xml.XmlException; import de.governikus.eumw.utils.xml.XmlHelper; import lombok.extern.slf4j.Slf4j; @@ -223,10 +232,70 @@ void testGetCertificate() throws Exception // Get the certificate Assertions.assertEquals("CN=jks-keystore", - configurationService.getCertificate("certificateName").getSubjectDN().getName()); + configurationService.getCertificate("certificateName").getSubjectX500Principal().getName()); } + @ParameterizedTest + @ValueSource(strings = {"rsa_saml_2048.cer", "ec_saml_224.cer"}) + void testGetSamlCertificateIsNullWhenKeySizeTooShort(String certificateName) throws Exception + { + var configuration = configurationService.saveConfiguration(ConfigurationTestHelper.createValidConfiguration(), + true); + configuration.getKeyData() + .getCertificate() + .add(new CertificateType("certificateName", + ConfigurationServiceTest.class.getResourceAsStream("/keys/" + certificateName) + .readAllBytes(), + null, null)); + configuration.getEidasConfiguration().setMetadataSignatureVerificationCertificateName("certificateName"); + configurationService.saveConfiguration(configuration, true); + ConfigurationException configurationException = Assertions.assertThrows(ConfigurationException.class, + () -> configurationService.getSamlCertificate("certificateName")); + Assertions.assertTrue(configurationException.getMessage() + .startsWith("The certificate does not fulfill the eIDAS crypto requirements: ")); + } + + @Test + void testGetSamlCertificateThrowsExceptionWhenExplicitECIsUsed() throws Exception + { + var configuration = configurationService.saveConfiguration(ConfigurationTestHelper.createValidConfiguration(), + true); + configuration.getKeyData() + .getCertificate() + .add(new CertificateType("certificateName", + ConfigurationServiceTest.class.getResourceAsStream("/keys/ec-explicit-curve.cer") + .readAllBytes(), + null, null)); + configuration.getEidasConfiguration().setMetadataSignatureVerificationCertificateName("certificateName"); + configurationService.saveConfiguration(configuration, true); + ConfigurationException configurationException = Assertions.assertThrows(ConfigurationException.class, + () -> configurationService.getSamlCertificate("certificateName")); + Assertions.assertEquals("The certificate does not fulfill the eIDAS crypto requirements: Certificate is not valid for that purpose because of " + + "reason Certificate with subject CN=TEST csca-germany, OU=bsi, O=bund, C=DE and serial 1264 does not use a named curve.", + configurationException.getMessage()); + } + + @ParameterizedTest + @MethodSource("validMetadataVerificationCerts") + void testGetSamlCertificateIsPresentWithValidKeySize(String certificateName, String serialNumber) throws Exception + { + var configuration = configurationService.saveConfiguration(ConfigurationTestHelper.createValidConfiguration(), + true); + configuration.getKeyData() + .getCertificate() + .add(new CertificateType("certificateName", + ConfigurationServiceTest.class.getResourceAsStream("/keys/" + certificateName) + .readAllBytes(), + null, null)); + configuration.getEidasConfiguration().setMetadataSignatureVerificationCertificateName("certificateName"); + configurationService.saveConfiguration(configuration, true); + X509Certificate metadataVerificationCertificate = configurationService.getSamlCertificate("certificateName"); + // Get the certificate + Assertions.assertEquals(new BigInteger(serialNumber), + metadataVerificationCertificate.getSerialNumber()); + } + @Test void testGetServerURLWithEidasContextPath() throws Exception { @@ -265,6 +334,96 @@ void testConfigurationValidity() throws Exception Assertions.assertDoesNotThrow(() -> configurationService.saveConfiguration(invalidConfig, false)); } + @ParameterizedTest + @ValueSource(strings = {"/configuration/metadata-9444-shortcrypt-ec.xml", + "/configuration/metadata-9444-shortsign-ec.xml"}) + void testGetProviderUnusableShortEc(String metaFile) throws Exception + { + // prepare valid configuration + EidasMiddlewareConfig validConfig = ConfigurationTestHelper.createValidConfiguration(); + validConfig.getKeyData() + .getCertificate() + .add(new CertificateType("sigCert", + ConfigurationServiceTest.class.getResourceAsStream("/configuration/metadata-signer.cer") + .readAllBytes(), + null, null)); + validConfig.getEidasConfiguration().setMetadataSignatureVerificationCertificateName("sigCert"); + + // and add metadata with short key + byte[] metadataBytes = ConfigurationServiceTest.class.getResourceAsStream(metaFile).readAllBytes(); + final String entityId = "https://localhost:9444/eIDASDemoApplication/Metadata"; + ConnectorMetadataType meta = new ConnectorMetadataType(metadataBytes, entityId); + validConfig.getEidasConfiguration().getConnectorMetadata().add(meta); + configurationService.saveConfiguration(validConfig, false); + + // try to load short key metadata + ConfigurationException e = Assertions.assertThrows(ConfigurationException.class, + () -> configurationService.getProviderByEntityID(entityId)); + Assertions.assertTrue(e.getCause() instanceof ErrorCodeException); + Assertions.assertEquals("Certificate is not valid for that purpose because of reason Certificate with subject CN=Wurst, OU=Autent A, O=Governikus, L=Bremen, ST=Bremen, C=DE and serial 1701967321 does not meet specified minimum EC key size of 256.", + e.getCause().getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {"/configuration/metadata-9444-shortcrypt-rsa.xml", + "/configuration/metadata-9444-shortsign-rsa.xml"}) + void testGetProviderUnusableShortRsa(String metaFile) throws Exception + { + // prepare valid configuration + EidasMiddlewareConfig validConfig = ConfigurationTestHelper.createValidConfiguration(); + validConfig.getKeyData() + .getCertificate() + .add(new CertificateType("sigCert", + ConfigurationServiceTest.class.getResourceAsStream("/configuration/metadata-signer.cer") + .readAllBytes(), + null, null)); + validConfig.getEidasConfiguration().setMetadataSignatureVerificationCertificateName("sigCert"); + + // and add metadata with short key + byte[] metadataBytes = ConfigurationServiceTest.class.getResourceAsStream(metaFile).readAllBytes(); + final String entityId = "https://localhost:9444/eIDASDemoApplication/Metadata"; + ConnectorMetadataType meta = new ConnectorMetadataType(metadataBytes, entityId); + validConfig.getEidasConfiguration().getConnectorMetadata().add(meta); + configurationService.saveConfiguration(validConfig, false); + + // try to load short key metadata + ConfigurationException e = Assertions.assertThrows(ConfigurationException.class, + () -> configurationService.getProviderByEntityID(entityId)); + Assertions.assertTrue(e.getCause() instanceof ErrorCodeException); + Assertions.assertEquals("Certificate is not valid for that purpose because of reason Certificate with subject CN=Wurst, OU=Autent A, O=Governikus, L=Bremen, ST=Bremen, C=DE and serial 1701967541 does not meet specified minimum RSA key size of 3072.", + e.getCause().getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {"/configuration/metadata-9444-explicit-crypt.xml", + "/configuration/metadata-9444-explicit-sign.xml"}) + void testGetProviderUnusableExplicit(String metaFile) throws Exception + { + // prepare valid configuration + EidasMiddlewareConfig validConfig = ConfigurationTestHelper.createValidConfiguration(); + validConfig.getKeyData() + .getCertificate() + .add(new CertificateType("sigCert", + ConfigurationServiceTest.class.getResourceAsStream("/configuration/metadata-signer.cer") + .readAllBytes(), + null, null)); + validConfig.getEidasConfiguration().setMetadataSignatureVerificationCertificateName("sigCert"); + + // and add metadata with short key + byte[] metadataBytes = ConfigurationServiceTest.class.getResourceAsStream(metaFile).readAllBytes(); + final String entityId = "https://localhost:9444/eIDASDemoApplication/Metadata"; + ConnectorMetadataType meta = new ConnectorMetadataType(metadataBytes, entityId); + validConfig.getEidasConfiguration().getConnectorMetadata().add(meta); + configurationService.saveConfiguration(validConfig, false); + + // try to load short key metadata + ConfigurationException e = Assertions.assertThrows(ConfigurationException.class, + () -> configurationService.getProviderByEntityID(entityId)); + Assertions.assertTrue(e.getCause() instanceof ErrorCodeException); + Assertions.assertEquals("Certificate is not valid for that purpose because of reason Certificate with subject CN=TEST csca-germany, OU=bsi, O=bund, C=DE and serial 1264 does not use a named curve.", + e.getCause().getMessage()); + } + @Test void testGetProviderWithErrors() throws Exception { @@ -284,38 +443,39 @@ void testGetProviderWithErrors() throws Exception @Test void testGetProvider() throws Exception { - // Prepare configuration with certificate and two metadata entries, one with a valid signature and the other one is + // Prepare configuration with certificate and three metadata entries, one with a valid signature and certificates, + // one with a valid signature and invalid certificates and the other one is // invalid EidasMiddlewareConfig validConfig = ConfigurationTestHelper.createValidConfiguration(); validConfig.getKeyData() .getCertificate() .add(new CertificateType("sigCert", - ConfigurationServiceTest.class.getResourceAsStream("/configuration/sigCert.crt") + ConfigurationServiceTest.class.getResourceAsStream("/configuration/metadata-signer.cer") .readAllBytes(), null, null)); validConfig.getEidasConfiguration().setMetadataSignatureVerificationCertificateName("sigCert"); + + // Valid metadata signature and valid certificates validConfig.getEidasConfiguration() .getConnectorMetadata() - .add(new ConnectorMetadataType(ConfigurationServiceTest.class.getResourceAsStream("/configuration/demo_epa.xml") - .readAllBytes(), - "https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa")); - validConfig.getEidasConfiguration() - .getConnectorMetadata() - .add(new ConnectorMetadataType(ConfigurationServiceTest.class.getResourceAsStream("/configuration/demo_epa_20.xml") + .add(new ConnectorMetadataType(ConfigurationServiceTest.class.getResourceAsStream("/configuration/metadata-9443.xml") .readAllBytes(), - "https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_20")); + "https://localhost:9443/eIDASDemoApplication/Metadata")); + + // Invalid metadata signature validConfig.getEidasConfiguration() .getConnectorMetadata() - .add(new ConnectorMetadataType(ConfigurationServiceTest.class.getResourceAsStream("/configuration/demo_epa_invalid.xml") + .add(new ConnectorMetadataType(ConfigurationServiceTest.class.getResourceAsStream("/configuration/metadata-9445-invalid.xml") .readAllBytes(), - "https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid")); + "https://localhost:9445/eIDASDemoApplication/Metadata")); configurationService.saveConfiguration(validConfig, false); // Get Provider - Assertions.assertNotNull(configurationService.getProviderByEntityID("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa")); - Assertions.assertNotNull(configurationService.getProviderByEntityID("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_20")); - Assertions.assertThrows(ConfigurationException.class, - () -> configurationService.getProviderByEntityID("https://demo.mein-servicekonto.de/EidasNode/ConnectorMetadata?SP=demo_epa_invalid")); + RequestingServiceProvider providerByEntityID = configurationService.getProviderByEntityID("https://localhost:9443/eIDASDemoApplication/Metadata"); + Assertions.assertEquals("https://localhost:9443/eIDASDemoApplication/Metadata", providerByEntityID.getEntityID()); + ConfigurationException configurationException = Assertions.assertThrows(ConfigurationException.class, + () -> configurationService.getProviderByEntityID("https://localhost:9445/eIDASDemoApplication/Metadata")); + Assertions.assertEquals("The signature check failed.", configurationException.getCause().getMessage()); } @Test @@ -364,4 +524,13 @@ void testGetDvcaConfiguration() throws Exception Assertions.assertNotNull(dvcaConfiguration); Assertions.assertEquals(configuration.getEidConfiguration().getDvcaConfiguration().get(0), dvcaConfiguration); } + + static Stream validMetadataVerificationCerts() + { + return Stream.of(Arguments.of("rsa_saml_3072.cer", "1669970371"), + Arguments.of("rsa_saml_4096.cer", "1669970742"), + Arguments.of("ec_saml_256.cer", "1669970936"), + Arguments.of("ec_saml_384.cer", "1669970973"), + Arguments.of("ec_saml_521.cer", "1669971052")); + } } diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgentTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgentTest.java index 3d798bbe..4f0bc7a8 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgentTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/server/monitoring/SNMPAgentTest.java @@ -41,7 +41,6 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; -import org.springframework.util.SocketUtils; import de.governikus.eumw.config.EidasMiddlewareConfig; import de.governikus.eumw.config.ServiceProviderType; @@ -53,6 +52,7 @@ import de.governikus.eumw.poseidas.server.pki.TerminalPermission; import de.governikus.eumw.poseidas.server.pki.TerminalPermissionAO; import de.governikus.eumw.poseidas.service.MetadataService; +import org.springframework.test.util.TestSocketUtils; @ActiveProfiles("db") // Use application-db.properties @SpringBootTest @@ -85,7 +85,7 @@ class SNMPAgentTest @DynamicPropertySource static void snmpProperties(DynamicPropertyRegistry dynamicPropertyRegistry) { - snmpPort = SocketUtils.findAvailableUdpPort(); + snmpPort = TestSocketUtils.findAvailableTcpPort(); dynamicPropertyRegistry.add("poseidas.snmp.agentport", () -> snmpPort); } diff --git a/poseidas/src/test/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBeanTest.java b/poseidas/src/test/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBeanTest.java index 7f1ad350..8816b705 100644 --- a/poseidas/src/test/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBeanTest.java +++ b/poseidas/src/test/java/de/governikus/eumw/poseidas/server/pki/TerminalPermissionAOBeanTest.java @@ -18,7 +18,7 @@ import java.util.Optional; import java.util.concurrent.locks.ReentrantLock; -import javax.xml.bind.DatatypeConverter; +import jakarta.xml.bind.DatatypeConverter; import org.apache.commons.lang3.ArrayUtils; import org.hamcrest.MatcherAssert; diff --git a/poseidas/src/test/resources/TEST_csca_germany.cer b/poseidas/src/test/resources/TEST_csca_germany.cer index 6ae8ee8e..1d61492c 100644 --- a/poseidas/src/test/resources/TEST_csca_germany.cer +++ b/poseidas/src/test/resources/TEST_csca_germany.cer @@ -1,7 +1,7 @@ -----BEGIN CERTIFICATE----- -MIIFOzCCBJ6gAwIBAgICBLAwCgYIKoZIzj0EAwQwRjELMAkGA1UEBhMCREUxDTAL +MIIFKjCCBI+gAwIBAgICBPAwCgYIKoZIzj0EAwQwRjELMAkGA1UEBhMCREUxDTAL BgNVBAoMBGJ1bmQxDDAKBgNVBAsMA2JzaTEaMBgGA1UEAwwRVEVTVCBjc2NhLWdl -cm1hbnkwHhcNMTgxMjAzMDYzMzUwWhcNMzIwOTAzMjM1OTU5WjBGMQswCQYDVQQG +cm1hbnkwHhcNMjEwOTAyMDUyNjQ3WhcNMzUxMjAyMjM1OTU5WjBGMQswCQYDVQQG EwJERTENMAsGA1UECgwEYnVuZDEMMAoGA1UECwwDYnNpMRowGAYDVQQDDBFURVNU IGNzY2EtZ2VybWFueTCCAjgwggGvBgcqhkjOPQIBMIIBogIBATBMBgcqhkjOPQEB AkEAqt2duNvpxIs/1OauM8n8B8swjbOzydIO1mOcynAzCHF9TZsAm8ZoQq7NoSrm @@ -12,19 +12,19 @@ QcrqmGO8Le1dWqglOqEKLvHJi5rItX8RF6cr8se558GsTXf8lMrcCD5nmEBQt166 H3ji0NSNUNFoe5O5fV98bVBHQGpeaIs1Igm8ufgifd44XVZjMuzA6r+pz3gi/fIJ 9wAkpXsaoADFW4gfgRGy3N5JSl9IXlvKS9iKJ2Ou0corL6jwVAZ4zR4POtgIkgJB AKrdnbjb6cSLP9TmrjPJ/AfLMI2zs8nSDtZjnMpwMwhwVT5cQUypJhlBhmEZf6wQ -Rx2x04EIXdrdtYeWgpypAGkCAQEDgYIABC6SZnzSfg27pu1RwOndsb1g2fyf1DB3 -E7XTZSHYUZSura1FAhGcal9Fc3GZCPqHsCP/iya+g2v6DCn0LdsK0jMDcvd0QV9h -Cj4dbgL1/rHp3zqB9eVxLJLgRPvmlXA8l7aGZmIkRUqriqxqSZTkJM7xc2pr+Isg -aXfWRE5QcbDUo4IBmTCCAZUwHQYDVR0OBBYEFFOdsYcqrJGT12OS7oDZ5Zls+Zs7 -MA4GA1UdDwEB/wQEAwIBBjArBgNVHRAEJDAigA8yMDE4MTIwMzA2MzM1MFqBDzIw -MjIwMjAzMjM1OTU5WjAWBgNVHSAEDzANMAsGCQQAfwAHAwEBATBRBgNVHREESjBI +Rx2x04EIXdrdtYeWgpypAGkCAQEDgYIABHn7RQMmq3Dn8Rlgu8CI2ar/XuTMT7zh +EuagMt9gQnjnzSrHBMqQwKPfIL9cM9EE4PzMBi/TpxcSBiu3XXQawrUmcbM0w/Vt +7dPNOZGQvxyEldZ9IlkAxfLAd7bbzEr9jC9JjNikiu5pgAYkcT+qDOWXKolhAoxx +C1zXQ8j7R9i9o4IBijCCAYYwHQYDVR0OBBYEFOT5NO5e2Y1hw/LvGknykIAdCPu5 +MA4GA1UdDwEB/wQEAwIBBjArBgNVHRAEJDAigA8yMDIxMDkwMjA1MjY0N1qBDzIw +MjQxMTAyMjM1OTU5WjAWBgNVHSAEDzANMAsGCQQAfwAHAwEBATBRBgNVHREESjBI gRhjc2NhLWdlcm1hbnlAYnNpLmJ1bmQuZGWGHGh0dHBzOi8vd3d3LmJzaS5idW5k LmRlL2NzY2GkDjAMMQowCAYDVQQHDAFEMFEGA1UdEgRKMEiBGGNzY2EtZ2VybWFu eUBic2kuYnVuZC5kZYYcaHR0cHM6Ly93d3cuYnNpLmJ1bmQuZGUvY3NjYaQOMAwx CjAIBgNVBAcMAUQwEgYDVR0TAQH/BAgwBgEB/wIBADA1BgNVHR8ELjAsMCqgKKAm -hiRodHRwOi8vd3d3LmJzaS5idW5kLmRlL3Rlc3RfY3NjYV9jcmwwDQYHZ4EIAQEG -AQQCBQAwHwYDVR0jBBgwFoAUU52xhyqskZPXY5LugNnlmWz5mzswCgYIKoZIzj0E -AwQDgYoAMIGGAkEAqFl+bu61fyYn3/roYr1UH7PTUSD4C6rapXsN4lkxkoQRRTja -h/u0ZGr4MFiHvKcUwGbT9tQSL9IlLl9yAz0y1AJBAIDU4qD8a4ie5YVGdUqF6Bxb -bssvqgfcmvCnQdjADDVaBVgdMzNy3Rn8qFsJisUNPUAtBwa8pAeVJ7o1RIYmYj4= +hiRodHRwOi8vd3d3LmJzaS5idW5kLmRlL3Rlc3RfY3NjYV9jcmwwHwYDVR0jBBgw +FoAU5Pk07l7ZjWHD8u8aSfKQgB0I+7kwCgYIKoZIzj0EAwQDgYgAMIGEAkAW/zUt +QwLAYqGY7qALAWhBylbD9dkdnxEtuiYiEsNs4hFy88FtDIPuCBgd8fISvRhOB5vW +YK6KZuPlUEyx6npSAkAIwFKXgnW+edyKe3flzjE2iglUodOKhEIh6ZwV3nDKC2JU +LVIQoaJ+LnZLfqoLO4xtWeRVLXgQxC2JUQzWRDiM -----END CERTIFICATE----- diff --git a/poseidas/src/test/resources/configuration/brainpoolP512r1-explicit.p12 b/poseidas/src/test/resources/configuration/brainpoolP512r1-explicit.p12 new file mode 100644 index 0000000000000000000000000000000000000000..002b0cdce54d1bf3f8d4c29b8c4c7efc343c7f56 GIT binary patch literal 2338 zcmai$c{CJ?7sqEec53X#l08c!Ya)^@DWs5HW8WrYYcOakS+Yx6CTsRB*+s@g&yxLF ziXmf<7>ZweBf5$FX#Kro5`ABEAMjWmedWd_m#a|rNG z2mwwyv0G6DsP>;0EQbJ9II+%wfPj-C`KJR!S^O4IW|SdH>W^eX@k8JvxT(R4MC%X` z2o69o!QlVf2BL=oP)HcPL!<%F84LlQg|HQx@N$*!F`hS?uQbfh&4`L1K-v#C%E)Rz zZ~KohU_Zj}e5+$~BIwgAMj9KrEp4MjVC5c637_BFz_dmkV`QS*8CX~eJ9dTcX$(kS z3egHnh%E)SaFd8WPanVSkS2T4HqB|TL}tb&l#LqO+GgL!Jv+EQME*MF`BcI|vvs}m z^Ek&;%}~mwVwKa}wHGaa2)qm~cD2E@1L zi~*O@C!~3l#53HW97nT;vFfZe9qTp0soG&2dSDCe%&^L}rCPN=rx#R`Ofu?>bk5j* zP>{4aHP0k1jn((pA(scEIi_86CzR_c_v*dA?(?J^_zpyBbO}wnqoBEP{PpM2%>1%SYc4|y%SOD^l@68^V>Y?qXV%`Kc zj(i#(Y*2Z-iOk1Mil(JyI6v9rZBxEh9PCf771OYJ2ne4tbSo0sL5~uG=6Q3bV>-CK zY7sE$AKjBFFfTf)Uuvfm&A*6g_%{f*rpCY&Gs^U;^icNV~o7WHhm((k`) zKij9YuB#6ysu|-}JK=UeCOshdL(ALHv++tQ1xl8T{aWmI?IwvJ!>)BQrMc~X#S%sq zs0oLqdv&mw@wuO?>>V#NRXu2M^J76;EXcCwK+EX#{{DL2wti7}DSmlKhifnL$_&e1 zSCaRY&9A1P^6L=6@OwnDqrmMK)`iO9{K?bsI_2O*z3Z7waP3qR+hKim3FUWO0f`3* zOj`kZuX6QdSo>F%=4SsI>$vFk`Zbl&V5w56T6>G&@QPOJ@UYng2eI7NTKwsFbthm^0Tsu4zq|p%JzpBg6lb~Q7%EAdH&6Q6VuNn zv<-)hLxN6sB7L=HPz12wZyx>&Sg;d>0CqUBZBEh>#`u5sGBE%_IRp?5MF6e;7f^ee zqT05seQy0HP>pL#*SO3r1Ze!1z_}Lu?GOSe(cbl&8NSR%fXEu(e7seC10C7W)bZU| zZOw#S615Y<{HASarO~)X`Z|dzxbR~A$C>H~^xM9>)~9ykw2vf9pp*M#41tHggCU#Z z%OsZBEvjpd+_rG_s{jzv`7}91MCYvUp2>M0C*F5llAw4M3~o_%a;LJssBkwU4d{@Z z`xVNj4@7T_qZy8x@!JWD_jU^k*h&_`7A_B-t~8jI9?}u3X*J&2L{h@9<-uHaeQRPS zCh9m;#%gEx86IJs5h_4sbT_@`nP3=mryh_zs<&@3=U@}Vn=`KPKt(B{F)KG(u+BJ{ zzgFy8mUp^ehHF}+D2A*eULKB+fiJ%l&nPnMW))8pgwGIu5@*+gAWFvb7Zgj;V71T# zrxp`B$;O+pjzkqz&4R^XpEO8P?6E~Rz3yd#W1qS&&rhNPF6U!MHO3{+DwfYXy_}PJ zd+@=JN`hPfs*}*weP$Sr>d703)A$6vA3HL?#}J_Mn3GELO?$tO6?r|)UX>Oo2wyG< z>`^g2J+6a=)DF7-MR}gI;=80X=7>&~tA2!e75`X)=QCtin8J27zd=Ce%;T&hBW~Hu zn#cf~K*Qt(t9Nnrf#f{?iv`!&S5itN1bDQ)zF&s=gbZq9kFViyEAB(3hBkdp|Hcgo`e1r$S!yK}@bab6&h6(3f<8 zIhtoJdO2|`of+z{@4RCk0ki*xb(e}!I80$23_{bhm$Zi+z1EAZi(irr%zDC;;@^}o z%Ju3x6!yea{uWB)_kqxJ$a6vv7G1Mxl@7+oS&h?CHe`4xH*0hvCz<>Pz;p if@zjB-XBK97#1gWc`!V)I0(D}&ls1pItKmsvi<>%NG^u} literal 0 HcmV?d00001 diff --git a/poseidas/src/test/resources/configuration/demo_epa.xml b/poseidas/src/test/resources/configuration/demo_epa.xml deleted file mode 100644 index 5ee3ea68..00000000 --- a/poseidas/src/test/resources/configuration/demo_epa.xml +++ /dev/null @@ -1,68 +0,0 @@ - - -czRU/izF/1iBRfAkD4yYFA1NMeyJw5Ahy7T7elvypas=UJXC1AgyWevFCbcURsAcYvXAYqkUli7s5y8SxJDUZ6/PBnINQaRSQVsKLxMPuXUZyacmlIMAamUO6Q84Y07SEOT72KvejHw189PeNKKO++Cpa0/mopnH8cwfl71z6PfrHj1fCOVr6ka/L9IoAtwUDVF0xRrNkxtk7JBUGJnWhKG6h00IKftzQUADhjB0ovsG1MLEa6u5uEyUI4XFrzE+vAgrnbV5eC6A9ECk53dag6BBefpXep8t44kJbYPaH0LQogDIcnDmYt0az6+BjbCnk01ubgvvS8o8mK8LHGSL5nUcWj+8OtONiftSxRk12HaPcOh3DSp4p+HRcAFpfaHw8g==MIIDVjCCAj6gAwIBAgIEWh62nDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQGEwJERTEPMA0GA1UE -CAwGQnJlbWVuMQ8wDQYDVQQHDAZCcmVtZW4xFjAUBgNVBAoMDUdvdmVybmlrdXMgS0cxJDAiBgNV -BAMMG1Rlc3QgLSBNZXRhZGF0YSAtIFNpZ25hdHVyZTAeFw0xNzExMjkxMzMxMDhaFw0xODExMjkx -MzMxMDhaMG0xCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCcmVtZW4xDzANBgNVBAcMBkJyZW1lbjEW -MBQGA1UECgwNR292ZXJuaWt1cyBLRzEkMCIGA1UEAwwbVGVzdCAtIE1ldGFkYXRhIC0gU2lnbmF0 -dXJlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjghvL1c6lm5ZhfLjrOwgFmQBYAXU -AR+4DsgkfObx2KKuEWttg6KuRcdKfE/B3l/+KuydVnYD8DseLPnaZlKV3JChLllPxOEEcHWeFaBJ -nMnzUv32lJwm78mRVAaxqI7hqKYbMCjMd3sasr8mbn+Rr1o/QSvumfcD3WkIzDOnQLJy1FSCizNy -AhqRJ5uQoZaBbhMllePZ4gyr7/1hhqkzYsQ1XCbBZGHZaZ5fZywiwaX5hGpsX+GG3j5wNtkiHCs4 -0+SAyZvQa8vxN3jlD1iIATU3CGGQmi8mItLjtvsiPNfU3yO4ajHoGxtgtn5evAEaqkH7e90VIexI -dLWiRFfE1wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAqu1FqrfNaWCupq/NRIfUFQ1bshovPoz4u -yHzXkAqAJK3PGO+fD/+PYVndMgeFKlSMGmNGDbY4rf9uVoZrgURpOA6tkXQ/UKz7YEDyuhjNVvXw -uMq3pwv9EyI+EYN5FslOxfSrUxPexnoi0bJfbxOk0Qd8HwfonIMn8LyFoKl5G77BLGT2ggmn0DR+ -dZxcNuDuf6EXGt9QD8eqKJKnZq4y7Cj1DnllpBRJXjJFp9UvDkaeS4P2KuUnsJ3oMt+l9wvD4Lfh -xu406Nps0BrrQlpPnlRIpICUY+T1lEINcATPfxYMJAuQy7dNdHA17gRA/DWN5bvdP7pK3Zjx2+xi -rLSJprivateMIIEyDCCArCgAwIBAgIEW9GX+DANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtUZXN0IC0gZGVt -b19lcGEgLSBTaWduYXR1cmUwHhcNMTgxMDI1MTAxNjI0WhcNMjIxMDI1MTAxNjI0WjAmMSQwIgYD -VQQDDBtUZXN0IC0gZGVtb19lcGEgLSBTaWduYXR1cmUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQCsO0qd/kdRI5kHsZPbG3ghHygOWpz6CnTcX/T29nR8BwBszZYRKc5k8dNIQqZbHyZ4 -DGuw1uxmcBDap6j/c9/Pegs3hNFQ1zlZQ8zT7ivifXcGhl2u6v2DlGl3bDBePXRqY1y3dngt0jiI -Wiy4IuSXJgTIQm0jMQMG95ndEwV2RwpXSWBTn6YRL6HHk9d1qRR8FE0OL4MyHPxVkOQ12EVUiG29 -/kQNkzCzrRUgYYwCORXleYBMuY4pEQKzyjlEWlE5ypHwLc5RBfMR23pTdt4Ph7tDqMVZYpjI6L8l -hOLuU+Ojja23PNRYaRnSaNddk1k/mDOyIxgQHhd9nhWiCgL6Ak8TsQ4AXUaozN0iRv6Aw3A05cVs -oIkA0U2wAeqvho4lHZPpgos3RnRBkEaZT5EJt+Vzv2Ak9bpGCaLY4i7u1c8mrtVnlyhJkqZGTUg5 -EPuAzlG3fkeNq0XYfTe5YmgFPgzL6l0yEWB7Htb+VjuW0JbwAMVoILbQLucM6JFiBFMY4hoASWqT -li+oh8aeYW4zBjPAEHT2pfcLrB91GYHdljACXLfidy/2rHMgTLXpjNVIkuG6OrnZ52Y2GWckMt1U -qQA7tcwuqhJ36z+PiYFvXgi2PTphEX/CjceWvVJY3EjrzwqNWJ7R/nHvfH9WWPCFgFp4vuOj2SH3 -N5mCVuLNFwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQCUUB+2aAq8HEMi4KjYI6s3q4xgRaiIv9ps -emP/lsj/T1QpeztJWe6ZAPn6woJ97O5t2CUm+KolL38l6SWvSe+CCj3FyKgz5DOmEUhlncUq2i/B -tgEMGiedQT/+B89rmjZH99lz9xztKXwQsl/WQOgyZyQBdfVK44QvvxXn62sIyOZMQBc1Ty/lg0DA -lGhwPTUixEVLQoVFLM1u7NN8tjV7XGojSGVhROq/3Tben70IiV1VOBZKxA8W34riqtwqMYfXn910 -vUZeFfZFHi1mQWC1BTQBCiGsvJzWksaA4j8D4HeeCRzP+l/SEMJ2wSg6a2PwLZjyPJ1Liza2C0N+ -ToGhENUp6hx+UjJ2q+YOX9FYIIRld54FyHpSMyJf+YnRlEsCq2bcgH7lyo2QD5zhdxRea0mzQEiD -zeUENoOTCeEx5/9huZoq7HsDI7omMnajQBcDZRB2r9FvsgpbvVLT5mHMthMsh+snheS8TD3Jo/v+ -pWZWhE9JUE7IdsYCLFxCusUcMz48cOcNkYk/m6Dw/fbNwb9FtQ9LO2dP2NxywAR4nm0dgu2jsKjM -7yHawXqHERfhYj0QbEc5BKAWHS97xbPJpDH5HWfFf6ha1zx2IqfuxRs5GvP7ikMdpJS1TTlIusxP -lkUvRocf9c8/VAzs5DqoK77PfWGpikRHvcLnA4BMKg==MIIEyjCCArKgAwIBAgIEW9GY8TANBgkqhkiG9w0BAQsFADAnMSUwIwYDVQQDDBxUZXN0IC0gZGVt -b19lcGEgLSBFbmNyeXB0aW9uMB4XDTE4MTAyNTEwMjAzM1oXDTIyMTAyNTEwMjAzM1owJzElMCMG -A1UEAwwcVGVzdCAtIGRlbW9fZXBhIC0gRW5jcnlwdGlvbjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAKbxVGFriYpWpo2C+y+ZDmThN3+XoB7ginlCqgbwBKwkLgh2Knyx2nxFAnQNbWep -eMlusPL+fZzhsDL/ErXkoEI+1VzU49DZh+/qKkmgEC5XkCPrEmugb8IMOLNZNW8XPqWa6shyZ/Xh -XySGXgQM3H9IZwTrtMuI0eNTtxaDVEKORtJJAGtE89veS0bWYia7mGXosDWe8nxXxkHPC3J5QRNb -Fvj4gCCvxpmNsgxYQAt6rLr6G4orZd85B2+yg6SNakmmk3o7uPGyQ8Llp2HtI5Z8pP8h+8sypm6W -ng4fTiqKg0d+RwmilcoIsXi/s2Rocdu4AIL7skLZ5im95PCRKITCop8+5QwlPTS2k3g2UXORVIEa -S8fGoy04mzRACCq1I4GkyNvL2eukpNV075JQ7n+9XhICKOkW7Y/B2tz+bzXmvX4H9h5X/6bJGQUp -MMcEc8B9v7qHo0A4UAeuixAdHhHoKJY/3sFI2JLYY5jpe2Il/GFEGv30/XAmIIV9A7dtXe338cgB -Jn/OGCy/6/UAfZiHYvmf/XLmNnw48flWWs1jGgnc/nWhRIy5cCz+vPJsDAaMqTY4nzb8f+urvt1L -qUsZ4OOmY8eDhkcu1XWoCSJ5xgU58GcIhZMmumkU93ea4DMXygIQjcUZ/hUDLaFK0BNtwNlZ/jEZ -fw/0kMRKJw2VAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAHjQ2Hobl4RFXNsmx3VBJs0rKRlHZTKW -YJnJ4TRAienLf3hZovUzyuNSUffVCzIcmkCm8Pq0BWXzQNwCJz3MAnCfBg6kXzjjORUbK1eFqDIk -Ei8eqGtvF9TlATYwXwcHOy6SXFQpMJ7zgOpy1GivxRv9L/JhZWu3m3BkdVEKqDt6DdZcFk5qLSNe -w9Ib85GLDdsSsEjR1K9UAygLp+KzDRjuUjy8bmsLKAJXeBimtIuFD/x3cOXKyxatjMVVwkwDL5TB -oyCRbV/quTCYbY6j2GpI0JGIXS2busSyXkWF7F3U/3BPUW3/qTGGr9eMu0WS/DFe0AWdXt8Yz58M -6va+9WnkazDDUjC/hBbtXYJG7KICqK+enu9pUJVStybGvoJeJMBxk4AeRgbhO8vPpBAlWVn8RiFW -tfUQJlgKG+uhl2OSpEBQ2ozqsbvRdx+DbxIZSPWGQA+dwoljqqQ5BwUmMkkpqNbMUBUeWtX1Ftgy -OFUlCXNFWeQhc+FkH3XNy5SeAQpdD8K2uCH/LALgXR0TAssEO4rhbB4kLHsx/FrhKMwNMtazRzpt -s5BQhaGq56g/YBMcXn51h15XK2rGg7lU+EwrGznMxTJfxCQMZKJ/G0qfz4/pgRiTrJyZjO1v05/y -G58FkfrZkNP/v2G2lfIVHW28qrfBfPBnQRkdvEnMWaeeurn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifiedSample Country ConnectorConnectorhttps://connector.sample/infoeIDAS Connector OperatorJohnDoecontact.support@eidas-connector.eu+40 123456eIDAS Connector OperatorJohnDoecontact.technical@eidas-connector.eu+41 123456 diff --git a/poseidas/src/test/resources/configuration/demo_epa_20.xml b/poseidas/src/test/resources/configuration/demo_epa_20.xml deleted file mode 100644 index 047e74dd..00000000 --- a/poseidas/src/test/resources/configuration/demo_epa_20.xml +++ /dev/null @@ -1,46 +0,0 @@ -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 -Fd0IJCg=MIIDWjCCAkKgAwIBAgIEWh62VjANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJERTEPMA0GA1UE -CAwGQnJlbWVuMQ8wDQYDVQQHDAZCcmVtZW4xFjAUBgNVBAoMDUdvdmVybmlrdXMgS0cxJjAkBgNV -BAMMHVRlc3QgLSBDb25uZWN0b3IgLSBFbmNyeXB0aW9uMB4XDTE3MTEyOTEzMjk1OFoXDTE4MTEy -OTEzMjk1OFowbzELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJyZW1lbjEPMA0GA1UEBwwGQnJlbWVu -MRYwFAYDVQQKDA1Hb3Zlcm5pa3VzIEtHMSYwJAYDVQQDDB1UZXN0IC0gQ29ubmVjdG9yIC0gRW5j -cnlwdGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6g1K21caFt2UU5b3Ne4fbO -jFp6wea91rRmIJzCyblpCsB+bqBkrqOrAb+l9JAlfDBUdeZcV/rhceDcZS3GABadiuozTU8cmvEN -RlOiU08Elwu6Pz0v98iIbpio213qm8p07QEvusn0XIczPVsffJP6yHxzkiFu7xwggaiqAeWO1MQ9 -xVwwh6PjePVCUtKvGJ1gGPwEGxTBdfZbKkLPfY0QqVhNAdUF2qx5Jdc52ny8mMOjzH/3RM0DwPha -8pxB5LpzYzBZtxCOOtBeV6Be3QZwefZSgGB8oUguOz1zmcTpEQ67jf+YHwWoUVL+zoK+H0j2tdOA -UJrNI9UlOR4XSUECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsHlGNkexcitbUXOLZF73gLXnbgxE -QJNhXjgMR9nz0kDII576RceHh0XHzJWUpX7KAFCjOl777Il/IMHcHtdR1wrEhOyugTIVhm1JRzOg -D4Wsk7k7ThPUsWRH++mA7rdbmKDTBoi/3Uz7Ujc/aGyFEsAfvwk4wtJy2GdZoLbnMGuGr1Yu9vF/ -FsUitIhlSMclQbgOeuVAYmhU1eKuoE8H30FOefIxOunHdtV+N0NrqE2bwcxuY7UZD2l8JxpyPWK6 -nGhj9n1gpoO+9GwMYVb1uZj2o+ilsYwv1n7B8ZjwKIuZlWYj8ZebbbwdLnhCHP6GW+Wik1oVwbLe -NRWoERhasA==urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifiedSample Country ConnectorConnectorhttps://connector.sample/infoeIDAS Connector OperatorJohnDoecontact.support@eidas-connector.eu+40 123456eIDAS Connector OperatorJohnDoecontact.technical@eidas-connector.eu+41 123456 \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/demo_epa_invalid.xml b/poseidas/src/test/resources/configuration/demo_epa_invalid.xml deleted file mode 100644 index c4030473..00000000 --- a/poseidas/src/test/resources/configuration/demo_epa_invalid.xml +++ /dev/null @@ -1,46 +0,0 @@ -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 -Fd0IJCg=MIIDWjCCAkKgAwIBAgIEWh62VjANBgkqhkiG9w0BAQsFADBvMQswCQYDVQQGEwJERTEPMA0GA1UE -CAwGQnJlbWVuMQ8wDQYDVQQHDAZCcmVtZW4xFjAUBgNVBAoMDUdvdmVybmlrdXMgS0cxJjAkBgNV -BAMMHVRlc3QgLSBDb25uZWN0b3IgLSBFbmNyeXB0aW9uMB4XDTE3MTEyOTEzMjk1OFoXDTE4MTEy -OTEzMjk1OFowbzELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJyZW1lbjEPMA0GA1UEBwwGQnJlbWVu -MRYwFAYDVQQKDA1Hb3Zlcm5pa3VzIEtHMSYwJAYDVQQDDB1UZXN0IC0gQ29ubmVjdG9yIC0gRW5j -cnlwdGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6g1K21caFt2UU5b3Ne4fbO -jFp6wea91rRmIJzCyblpCsB+bqBkrqOrAb+l9JAlfDBUdeZcV/rhceDcZS3GABadiuozTU8cmvEN -RlOiU08Elwu6Pz0v98iIbpio213qm8p07QEvusn0XIczPVsffJP6yHxzkiFu7xwggaiqAeWO1MQ9 -xVwwh6PjePVCUtKvGJ1gGPwEGxTBdfZbKkLPfY0QqVhNAdUF2qx5Jdc52ny8mMOjzH/3RM0DwPha -8pxB5LpzYzBZtxCOOtBeV6Be3QZwefZSgGB8oUguOz1zmcTpEQ67jf+YHwWoUVL+zoK+H0j2tdOA -UJrNI9UlOR4XSUECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsHlGNkexcitbUXOLZF73gLXnbgxE -QJNhXjgMR9nz0kDII576RceHh0XHzJWUpX7KAFCjOl777Il/IMHcHtdR1wrEhOyugTIVhm1JRzOg -D4Wsk7k7ThPUsWRH++mA7rdbmKDTBoi/3Uz7Ujc/aGyFEsAfvwk4wtJy2GdZoLbnMGuGr1Yu9vF/ -FsUitIhlSMclQbgOeuVAYmhU1eKuoE8H30FOefIxOunHdtV+N0NrqE2bwcxuY7UZD2l8JxpyPWK6 -nGhj9n1gpoO+9GwMYVb1uZj2o+ilsYwv1n7B8ZjwKIuZlWYj8ZebbbwdLnhCHP6GW+Wik1oVwbLe -NRWoERhasA==urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifiedSample Country ConnectorConnectorhttps://connector.sample/infoeIDAS Connector OperatorJohnDoecontact.support@eidas-connector.eu+40 123456eIDAS Connector OperatorJohnDoecontact.technical@eidas-connector.eu+41 123456 diff --git a/poseidas/src/test/resources/configuration/keystore.jks b/poseidas/src/test/resources/configuration/keystore.jks index 532f62285282737ebd15d4c5802d342e2f70064b..f7f9a5b47ac905393376fe9fc3c6915243a37e03 100644 GIT binary patch delta 3636 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 GZRUOkH{PTG delta 1972 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 Epin@$PXGV_ delta 2380 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 diff --git a/poseidas/src/test/resources/configuration/metadata-9443.xml b/poseidas/src/test/resources/configuration/metadata-9443.xml new file mode 100644 index 00000000..1652fa5b --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9443.xml @@ -0,0 +1,19 @@ + + + + + + + + + + +tdI4ncbeaoNmdwoOrHTOBkPTZAqnRleP8aJzQ3BhKkk= + + + +AIn5T274UBS3yG7ajt2OJrh7dCirUOha/lP4whKWAJiphYv5mwLo2Q0UDow0MAGoU6Gpy9RCdKNb +iy8XqURgxBZeAKsCR3i2DT2wstNhsSFoWLMBUhtGHKatll6Yq2+s03mmMr+FaIc+IaYO0MtLc10c +qmZibdLTA+l36mpseMRVKgGW + +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urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9444-explicit-crypt.xml b/poseidas/src/test/resources/configuration/metadata-9444-explicit-crypt.xml new file mode 100644 index 00000000..4d67956e --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9444-explicit-crypt.xml @@ -0,0 +1 @@ +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:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9444-explicit-sign.xml b/poseidas/src/test/resources/configuration/metadata-9444-explicit-sign.xml new file mode 100644 index 00000000..c84f9636 --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9444-explicit-sign.xml @@ -0,0 +1 @@ +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urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-ec.xml b/poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-ec.xml new file mode 100644 index 00000000..73bfe0b6 --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-ec.xml @@ -0,0 +1 @@ +publicMIIBmjCB/aADAgECAgRbKL37MAoGCCqGSM49BAMCMBIxEDAOBgNVBAMMB2VjLXNpZ24wHhcNMTgwNjE5MDgyNTMxWhcNMjgwNjE5MDgyNTMxWjASMRAwDgYDVQQDDAdlYy1zaWduMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBIB3MqDS3NIgvI8Q8xXv94Qik/GThW8YkXvTK12zxwLMyBd7TnLAEw8s/tZyQ7mQuH7ZfRRFzMzGoHG0oQL0K+rgAXfNVcFFHvwNu7z13wtCg2bUc1MMGBRCmw+OqM01DmEyMidN7ro02nTH+iXTAl4aLpUT6IahdkSNponlib4PFbV4wCgYIKoZIzj0EAwIDgYsAMIGHAkEBuy7RsH8BJ37dP4Pn/Dl6uz5pasIKbgk6pqtpmQFQr7xACG2XNW41aOUrr9prhj7hrvltZklhMKDAk1ivAgsQ3QJCAPESOq4/bKoWOOyuCMgMQgV72CHwGd1Fb/4Is50J3B2MNqesVzdpnbFbI4nNOT/lvZgob6iZwtM9MrmtA2smbLYEMIIBsDCCAV+gAwIBAgIEZXH12TAKBggqhkjOPQQDAjBnMQswCQYDVQQGEwJERTEPMA0GA1UECAwGQnJlbWVuMQ8wDQYDVQQHDAZCcmVtZW4xEzARBgNVBAoMCkdvdmVybmlrdXMxETAPBgNVBAsMCEF1dGVudCBBMQ4wDAYDVQQDDAVXdXJzdDAgFw0yMzEyMDcxNjQyMDFaGA8yMDU5MTIzMTIyNTk1OVowZzELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJyZW1lbjEPMA0GA1UEBwwGQnJlbWVuMRMwEQYDVQQKDApHb3Zlcm5pa3VzMREwDwYDVQQLDAhBdXRlbnQgQTEOMAwGA1UEAwwFV3Vyc3QwUjAUBgcqhkjOPQIBBgkrJAMDAggBAQUDOgAEXm8AApGZPgxWsz/Zj02PkCpuV1kZ/TO1XZ5QJSfYyq506NVv6K1gVKVCgPPKhdB0Vcgkw3me6TwwCgYIKoZIzj0EAwIDPwAwPAIcYh9P7oBYwc6PHaBK091wN5Q6VpTSqKLPTCIfcAIcZFTtcL4QRKcpC+lU2o91O4fNqMp5e8SXJiMnsg==urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-rsa.xml b/poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-rsa.xml new file mode 100644 index 00000000..0ff51070 --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9444-shortcrypt-rsa.xml @@ -0,0 +1 @@ +publicMIIBmjCB/aADAgECAgRbKL37MAoGCCqGSM49BAMCMBIxEDAOBgNVBAMMB2VjLXNpZ24wHhcNMTgwNjE5MDgyNTMxWhcNMjgwNjE5MDgyNTMxWjASMRAwDgYDVQQDDAdlYy1zaWduMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBIB3MqDS3NIgvI8Q8xXv94Qik/GThW8YkXvTK12zxwLMyBd7TnLAEw8s/tZyQ7mQuH7ZfRRFzMzGoHG0oQL0K+rgAXfNVcFFHvwNu7z13wtCg2bUc1MMGBRCmw+OqM01DmEyMidN7ro02nTH+iXTAl4aLpUT6IahdkSNponlib4PFbV4wCgYIKoZIzj0EAwIDgYsAMIGHAkEBuy7RsH8BJ37dP4Pn/Dl6uz5pasIKbgk6pqtpmQFQr7xACG2XNW41aOUrr9prhj7hrvltZklhMKDAk1ivAgsQ3QJCAPESOq4/bKoWOOyuCMgMQgV72CHwGd1Fb/4Is50J3B2MNqesVzdpnbFbI4nNOT/lvZgob6iZwtM9MrmtA2smbLYEMIIDTDCCAjSgAwIBAgIEZXH2tTANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJERTEPMA0GA1UECAwGQnJlbWVuMQ8wDQYDVQQHDAZCcmVtZW4xEzARBgNVBAoMCkdvdmVybmlrdXMxETAPBgNVBAsMCEF1dGVudCBBMQ4wDAYDVQQDDAVXdXJzdDAgFw0yMzEyMDcxNjQ1NDFaGA8yMDU5MTIzMTIyNTk1OVowZzELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJyZW1lbjEPMA0GA1UEBwwGQnJlbWVuMRMwEQYDVQQKDApHb3Zlcm5pa3VzMREwDwYDVQQLDAhBdXRlbnQgQTEOMAwGA1UEAwwFV3Vyc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2hN06yVhyo/KIvnNHOipyTKPmdtBiN9OCtyFrS86nIq6Tb19IlCSbd4dqd1Gm64h0bBsz4sYZfsDVzat4w6GlsoVY0KUUWk8ZLbslHkym3S8Ryi49u4t0/OpF977xlE2vcHg7BpYWbiQzGavIhrw8E6WKvJ6HTUdNDlyz/RgQQ2UBW1cdCjc9y03RtER7aLjvofE+djnVCnmLLxPkxN26zFoxqOD4AGoWq0Vs/ivsaVnPCSQ8AoDG85Lv5Uq1t7fpLYeka54kZl3kDBcIQJe5eBmRuT6ouST/+2LwFyblw1HRNJj4pzVUuVaF+EtobImgsrMRpavtAIhfe+S4OrIPAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEUPcamZ6pIzg63jS/AmxIHUVkdTITTnl33vc6jcYf4UnUsHehurtC6QYTaJ3evQpD+tzLdZNWEJ5O4LaqzWVXXjC4Q2/BSKzWiI2H2a/uAx/YzOVl5enmQpQDp+LDf1aovWxtrKW1TBXw0gliaGmm/DnIGB/wdBw2GYnAZjJ8BydfuedVi1NuKdarb5Zpi///PGaIkIKvxIp1/EXx9EeAHQpvKuq8W7fzBYoIqZvVxHtkrnTns7JZwVd1OLxn8c+VHUXpDLzwkay1DzjCQUUOPR19v8TQIgV9LtNOmjottHit8Vy+LBw8X1Z/JG6RtieZtSdWLtLsrZ7FFzkQ8Lsic=urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9444-shortsign-ec.xml b/poseidas/src/test/resources/configuration/metadata-9444-shortsign-ec.xml new file mode 100644 index 00000000..536c6a7b --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9444-shortsign-ec.xml @@ -0,0 +1 @@ +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urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9444-shortsign-rsa.xml b/poseidas/src/test/resources/configuration/metadata-9444-shortsign-rsa.xml new file mode 100644 index 00000000..59b48294 --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9444-shortsign-rsa.xml @@ -0,0 +1 @@ +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urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9444.xml b/poseidas/src/test/resources/configuration/metadata-9444.xml new file mode 100644 index 00000000..92fc5f9f --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9444.xml @@ -0,0 +1,19 @@ + + + + + + + + + + +7kd7ST8ZbIbJdq8IK6yjFhn55Ist8Tbd8EyNHtIN1p0= + + + +AVfT9gMzmTgns7eWf43s4QBg0HJlDC54oI21pFgHzzfKtvfaL9tboxJy9VcHif5Dq59J9nGvop+i +B/Rsf4kf5PRPAUV3zXsiDAEg8/oo6C5K8nqU0oQT+ZE0Vq5Wpb/ihILUQYqC+t3q5ALuZWdbiY1h +XdEXzP22JCg4Ps0/NuYSEeu1 + +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urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo \ No newline at end of file diff --git a/poseidas/src/test/resources/configuration/metadata-9445-invalid.xml b/poseidas/src/test/resources/configuration/metadata-9445-invalid.xml new file mode 100644 index 00000000..eeba22cc --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-9445-invalid.xml @@ -0,0 +1,19 @@ + + + + + + + + + + +7kd7ST8ZbIbJdq8IK6yjFhn55Ist8Tbd8EyNHtIN1p0= + + + +AVfT9gMzmTgns7eWf43s4QBg0HJlDC54oI21pFgHzzfKtvfaL9tboxJy9VcHif5Dq59J9nGvop+i +B/Rsf4kf5PRPAUV3zXsiDAEg8/oo6C5K8nqU0oQT+ZE0Vq5Wpb/ihILUQYqC+t3q5ALuZWdbiY1h +XdEXzP22JCg4Ps0/NuYSEeu1 + +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urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifieddemodemodemodemodemodemodemodemodemodemodemodemodemo diff --git a/poseidas/src/test/resources/configuration/metadata-signer.cer b/poseidas/src/test/resources/configuration/metadata-signer.cer new file mode 100644 index 00000000..2d345927 --- /dev/null +++ b/poseidas/src/test/resources/configuration/metadata-signer.cer @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBmjCB/aADAgECAgRbKL37MAoGCCqGSM49BAMCMBIxEDAOBgNVBAMMB2VjLXNp +Z24wHhcNMTgwNjE5MDgyNTMxWhcNMjgwNjE5MDgyNTMxWjASMRAwDgYDVQQDDAdl +Yy1zaWduMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBIB3MqDS3NIgvI8Q8xXv9 +4Qik/GThW8YkXvTK12zxwLMyBd7TnLAEw8s/tZyQ7mQuH7ZfRRFzMzGoHG0oQL0K ++rgAXfNVcFFHvwNu7z13wtCg2bUc1MMGBRCmw+OqM01DmEyMidN7ro02nTH+iXTA +l4aLpUT6IahdkSNponlib4PFbV4wCgYIKoZIzj0EAwIDgYsAMIGHAkEBuy7RsH8B +J37dP4Pn/Dl6uz5pasIKbgk6pqtpmQFQr7xACG2XNW41aOUrr9prhj7hrvltZklh +MKDAk1ivAgsQ3QJCAPESOq4/bKoWOOyuCMgMQgV72CHwGd1Fb/4Is50J3B2MNqes +VzdpnbFbI4nNOT/lvZgob6iZwtM9MrmtA2smbLYE +-----END CERTIFICATE----- diff --git a/poseidas/src/test/resources/configuration/rsa-2048.p12 b/poseidas/src/test/resources/configuration/rsa-2048.p12 new file mode 100644 index 0000000000000000000000000000000000000000..c2e78e9cc58a250e50a78da1473c582d9d24c696 GIT binary patch literal 2524 zcma)8c{CJ^7N3=-F+yX>Iw5N_#*$qjlA*C=NtQ^2WX(=xWC_^^WnZ#|K?W)7$SB5V z`E1EPdPU+?{K&pr3I-2d+HTr2@L4g!L)1Q>w{CKYuxY8L@y2IdoB zz7PV;^Cx@{OMuq>7X>YX5TJQK;jEvP!36)0i{&H`luv+a{sh&r&c7T`1l9_x{Ci}< zN<)yx9EBIR1KuvsB<*D+kc0H4-6{?cNSqA>L}6K&PW*c#2nGdU1(;y=QCERZU6h;Rk z$~M76s;$P|b648rTDHe3VwmhcC6p6w?VYA3Ed$4JSQLVq7wm+v^<^BDEXx2Iuz~SL z-s?G_*cA5HrbE39LC|>8kYISBdrN8`c6h$N^zSxmZ##yk^PbC|qJ1$deP<=ZDI;Cc z9H1-zBqS|ljfW$6@>w>f;?$dI7oma^#pxdip-a8+*9l%Wu8*Bi>GJc;h) z(7SOWv8?v|j|C`pZG>B3PvgnNLxnfw%nVJse51fF$Jl#-!i^-l=u*!s6jG5n)y-;s zZ)>J2REJ05O8=mT^L})vO@wB2KKZk`!z;R_9)V--u6im<3CK|uJ@Tr#eC2Z-=t7tb zz43OV{?LSvL9OFa-;LUhEJZZ)QQC|YRREiP$@7Zybiu-}Y zOWTWJZr9u!-qIhxuUk2E>%g+~+bbkax%4WxCZqbBh19${vUQucxl2D{I)eSJqe+erG3>74{b#x zda|5s{Tj_a*Rs#X_Yu_ua>3nQ)fTD?$!&2y?|rgmC0EycL3$ZBw8M{?oz@ZkYq*|; zJDY;T8sF=wSQgi$n9yU+bNa`8z{n*k8g{5ztN(aU5|Iksk*hG z)3I09==V*Zzi(-QS(&`ZcRTboJDc-Hc}81f=jfkJm3Q@k)DXU-34trAoef{AapyV~ z8|WBhq~7g5D;d9DdE~RvUEI10FI5`f3ib~a4>oEk^Bk--FnQEaC|N}gp=#PUpr-K` z7ZkZ06MDj>h6izG?L?)Rd<9G!4yz)ze#f`Vq>PmgJ zUh-!G6RTd`GB+)YdFtG}EFS({wK3&Tl;5bm5$a#QH3z-bve%l>vi}?kPciZea2WC%%3XncgG1vF3gOM>6=rnMTlUSw215n8Rd z*D=|KhLbkSb)sKe4;Jj46u&)@j<$>7wIHotR9+nkF+P5~fcMN5+^At`t;`BHQ5ml% zDTK$%>R^R_#U%_W%OS`H@B#P&8~|v58~_VY04QV6{uXe`A|V`RuJ@f#vPxJvITa-p zS$R1nc`N~3`%A>klurN`{)BQtK)}zI@tXnuuc+R|kIWc(!>2ZyM^-%U3$=s-BQ^e? zsGint`cv%dfM$j{1EKI7FZ!4OM$Oo04p2l#u31P->?~s@C~RGkxcm!ebpTgW=m**} zr%i~#b_k=OoGyK)gt)_^c0R%3+QoKczJ_>$mB*`%){(cyfAH4qRygRg7*@mD-<>rv z`LVZU<9yvpaqfPm19P1}!u>kQQ}25%#i&y5GBaVI zdLut$UcgryvF!?Bl8gq_HEf6EP~tpKRK9c#{NvQt;TcR;JJ9g!Qgy#+D#D6VT5@8` z4B`q?JbS3Frf0A^82lsQt1f1{lzDMf;8d`c#qd4Ha?2*BSRW5}bRsCTY|Fzy!;LlS z1PW`}CAM1xK(yOljw&0uAl|I<$m3estTvb7bB06(OR`8lqZZPS zUxLe-W?SX5z;{r(_A{(5V1ou~Bheg$iJyf{N8^s8L)I>`vt3cBo+T5})>}nhbH%Gl zU!MVvI_iWzKKbhm;ah5aYQ37+l9W~idC=6{)MMt;*lSo>EaKP40|G(; z5R^kV>V~m4=<*a7)gX}0>3O~H!*EX@CqP$ni)Dm8 literal 0 HcmV?d00001 diff --git a/poseidas/src/test/resources/configuration/secp224r1.p12 b/poseidas/src/test/resources/configuration/secp224r1.p12 new file mode 100644 index 0000000000000000000000000000000000000000..de2d555275baca4100f221175e0da6e1a730891b GIT binary patch literal 1115 zcmXqLVhLwrWHxAGVPxafYV&CO&dbQoxS)yo6H62GJA)?XR|ZXti6~NxK`c#-en4R_ zAa-NphU((sVq{v-_|Bm5wLuzOJu9z4q=5y3%VVI;B62`q)Sct4?5FkhwigrE_vtoV z-^0noq%Oe3s9?au#sM*piIbJVK$eX&q0NIam6?T6i$&m?V#KB=U-<5v$&Py8Is3O6 zOJl?FuZR1)xsJN*Stiz2#=QGyn+VSyh3~SLgnl)$na#f~mnrXkLie%%F}=7IuXaZ- z-}0GTBSr99?;e%Z?YB*I<}b_t6_zV|^81X5wXd_B4ogcv*phg$H(o|>XU@YPo-=&R zPqZ&AsCgq2zq0J+wt&Q`TO{`XaaX;w(fw;#$Cs75mdgy?3>4wM;}kIzkrQGlW=Lg7 zW+-4V0zwmpA_hZbC8CBREJ7ifxv2_<<_1P4rpBfw#>S=w22D(jaC6w%7Bn#x0fq9I z7#V<6Izon#P}quzy{Xw?rhC$NUJ>8^&|Kz&VUiw9OdJe^!gd+&(J6NYjSEs&PTO)L zAoh4e6XS>Z$4)VST$J`%>qpI|YZAAPr0%QRHsSKu)#ooPbiHk|G~tl|2V4v(3w%YMqH z;>1+r*r-a5pWj!_Z9d88kh6)gqcI@Z;nSpm=e7dBSdJUJa_(ccFG`)*?D$r@vQ~T( z^OUG*i;~JWy^+~yxi_HUXwH?IloRzwUtFD5QlXT^k?>L6>95qv=8e;qgibuBu43le zQ`+g>SjF(B!Aduc>CRCd@o;U$WjlNJerIA#X^7E|Ta%r0+=XrRL^q$^jra3bs7pAB zED|Vt7@W5x)6ccsr~k_a)}`{i{%q3{LNCSIe7<2f?fLW4Snu!pbYM!DkKYzizi%$CkKgFP$@w>FI5@exLo*4kiEg z2}*7bk`l`H7BuiRFf`zWXE`QDRt6RYmFt!wi~`)T{1vl~aq&coN&T@<>T_=GJJ|hV i^HaT}48ZJcdBLvB^7PffpT+w99vf3g!fEsARGQmSU9YSUV^X{uChv1d`E z_Wb$&&O6Tg$34$IpXc0r|9j4bq9`BW;{l;4iUUGo!C1}M6EZw7UIB_?8HA#kzr{09 z6hZ3$SOk$E6hY`M4!SLWLXv+?k>0_>FF=9Lp(xNXl%Mda3BIqZg{npWt$&ov$U;elOa#cs$qBMJB10C%)|T@<|L zza@86q#q?78OrOXv)^Cxf1=;eNR{3~IjY3O4+~4cUt>CQ5J`&ge1hP(Fz-vISJO
}?rYGihKOn0RJ&=rn82=1Z{$8_XeSH4$%eML`wD)%egG=;^of=Lg*oxAhE z;DNYuW6B{~y`vJL%2G88D*u&3ov-gY%U%>M{3=gcr@mwzbs-H=*Ixb-6FAauzb5JO zO6DY@>8BAy86_JkRIh%RLaJ5daYUH({^DnthmFK9HwyJQJ(3B;)1lsL%`ji0Ws!7; z$LuLxO2rKdso~V{P6yhaj0bw`n(2|G6|16H4QXky=9a2CkyExpOz-eZt!j8@=E3Ii z!SQDu`3MAV$K{fb`!{?&!QQ4K^@=XYL0sUCD}NVnD<(BsHY8Xgiy@##m4`RCj1$gk zC2?c_&DbpolA&?lj6Xp2a*uFV4CcjqeSu!4l|%fUyF4mgSr?Ynx=BhKOMc4I{osI> z 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 lguky&f@~3JU~8kC<`|ab9PRKp@@MH zh{w#sotms$oS2)VYh+|%pdij`WMpV$U}RunVqs_;CBbiGU}l0OK%_Z-1_EsCV7r+Z z*;ut3Sr`D_iAE3ve)98cG=xn+EIABdiy53*Nu6B(bp2zN&)~ahg>}X literal 0 HcmV?d00001 diff --git a/poseidas/src/test/resources/keys/ec_saml_256.cer b/poseidas/src/test/resources/keys/ec_saml_256.cer new file mode 100644 index 0000000000000000000000000000000000000000..0767abca817a3d792325d57356e084b6d5af2374 GIT binary patch literal 316 zcmXqLVze-5e6WC-iIItkCAo9=4+AbX4y`tibG9tZOa>~3JU~8kC<`|ab9PRKp@@MH zh{w#sotms$oS2)VYh-F>pdij`WMpV$U}RunVqt0)CBbiGU}l0OK%_a52EuIYV7r+Z zp^ji?WM_6_V3DuC)*2)CE&uB`0nEUiEDTD_NenEHo+VCH{Fuhee(}ToLz~O5dMKIRJ~e3q-oi^;Ay|32o z;)2d2pQUb1adAp4{%;|?>+#CV51&3!xsq?PX~OfP8&9bx9ZoyEXPRJ4f>II(=T)B; zLsQOq-|ydE*n;e1=5z*w6efe%|GGD)pE>tVx+B|kox(j0yEB0gSvkXl=Q*mc*)+}h zc+;HFHOxzeo_wFHt#TwJU?!76jNp6;<=S=oEFT{FR`dJ2-Iu7!&#}L~!mKi{-I*l1 XAY8`(Z(KS{!p=iSw-{Od?pgo8;4e#$2nUTW+np_LmnWXIh2K)hdDbZ!%)OP z2*hLN;Z9A~El$kM(KR(PG*A%dH8L_ZGB7f*Ff}kWijv?rGB7hi5+Kr?#@Pk}Z0umm znHbqvwHsL&l$jgb7+4q-BPXnNKJeR@cl)}9Gu~*)9NfsQ`)>P+rJPf01ZO=t9Ahz8 z)zJIbnJG>!OLd}Zr|;NbeL8B}to)Y+qLf^Vpw>JiBZS2DYEBiO(Jj4jc?Ob zKJ9(O7jxay^7V|`8DXl|T(g%t*yZhVZd2N)V?XA z!ra)+V9?mkpjJ{fVmF%Qb)NWmkuE%O5dZXceoq`*N+Q>Cwb(yKWS-Pk$l5H0c5_GXSK9qeK7z literal 0 HcmV?d00001 diff --git a/poseidas/src/test/resources/keys/ecc2.p12 b/poseidas/src/test/resources/keys/ecc2.p12 new file mode 100644 index 0000000000000000000000000000000000000000..fee468b0f5435d3860dfe02aa39e16f10070cef9 GIT binary patch literal 1159 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 R)VuvUzuiv0X!)aRZvf|rw+jFO literal 0 HcmV?d00001 diff --git a/poseidas/src/test/resources/keys/rsa_saml_4096.cer b/poseidas/src/test/resources/keys/rsa_saml_4096.cer new file mode 100644 index 0000000000000000000000000000000000000000..6c5845caf37facfdc05e66909a43cb753b867d54 GIT binary patch literal 1222 zcmXqLVmV~c#I$MwGZP~d6H9XEZZiX3HcqWJkGAi;jEvl@3=ZjP>rfu)&&f;g{{k)e@+k%5JYsfkgP1iz7inF*2rQKmF8DIr_V z$jZRn#Kg}4bRQQ}6B8rDiX#Q5oaa_v&wtghIBLb=q@rTxi5$*vUT@_-cPH#xxVpB- zkH1we;dvU_HypO_pZw?g@|&s0uWBe|-o8}Gul>R3^0F-Je!UQ{uSb-(?I@Ak`jGJm zYf*il^Pi7_0hxLn)=>@{W}g4hw8wMCDyz#2yqHTSZ?l!3swt3sBKF_kZ;G8aPd829 zeehhon*`ILNmq>IXIz^o`qa08^E(GuN6Hbwqh|a|F3(plihp`*Z)oV-7oU9goh^M{ zvi(i#%U=(i-&Q4El1#cgK{3vAE`xUe3_jb7tG~Ok`a}!<}pkD8vu%gYw--_Y!;@=N%cCi#l${C&0afqn;lkiJYljAj?aiQ!_pN;7U58bmb zU&+OIcxkP5c)=@o=Nx@6u_hT)#j7e3!XK17-tXh&zV5=%cxQfh`wDI^mbNu%Vl8JT zw=*{?1ay3P+gI+}eyC}6XYXUbypw#~XSS65Shl{Z@6mM0<}|+P+S#Z7RW{U;P6L@Em5aVKcOEua z!=j<9w~2jwr*Zh>e$G`~2d8JgdGJS8W>dV^z5mJU?Ordt|IpCz%l6)@TPBx>PA@)Y zvvuZ^CcTDem-rB|b#9LiG)$D1?wRlH(wlNb{PhomZTsz+m>C%uky8jTc>+@iBZGc! z>NyD^6^00@_wR~2WQ=(A;tfL|9lmNts*j`>Z?MW@#@2K zTVF1&OWKpdqs>_|^WB44E*cDp^EOO#os-#WD0cJO%>czeE8fkVuk&k0`FdBSdY?On zo7B&7|Gpcs&Ou?}wak^Nsf$Cno& zjt}SDuOIIlXg%DyZ@rg@`}1A3?iz_DhHspo%&<>8 zP}Y9e?`iNOW?p;ay)|au`xi|4;dp-X`=F#i(Xl{@cOi_OMaKTYPr+-$6u2)`4V%^$T=SNf5Whg z)$;pP=i(`<({2{sUazG$eYwXE(O)HAm$KaBDwoXRoE-W de.governikus.eumw eumw - 3.1.2 + 3.2.0 utils @@ -24,15 +24,15 @@ org.bouncycastle - bcprov-jdk15on + bcprov-jdk18on org.bouncycastle - bcpkix-jdk15on + bcpkix-jdk18on org.bouncycastle - bctls-jdk15on + bctls-jdk18on org.apache.commons diff --git a/utils/src/main/java/de/governikus/eumw/utils/xml/XmlHelper.java b/utils/src/main/java/de/governikus/eumw/utils/xml/XmlHelper.java index 22833862..70cf37a7 100644 --- a/utils/src/main/java/de/governikus/eumw/utils/xml/XmlHelper.java +++ b/utils/src/main/java/de/governikus/eumw/utils/xml/XmlHelper.java @@ -16,10 +16,10 @@ import java.nio.charset.StandardCharsets; import javax.xml.XMLConstants; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Marshaller; +import jakarta.xml.bind.Unmarshaller; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; @@ -64,7 +64,7 @@ private XmlHelper() } /** - * this method will marshal any element that is annotated with {@link javax.xml.bind.annotation.XmlRootElement} + * this method will marshal any element that is annotated with {@link jakarta.xml.bind.annotation.XmlRootElement} * * @param object the annotated xml-object * @return the string representation of the xml-object