diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 51cfc367..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore index f5d73387..0eb47666 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,4 @@ build/ !/tools/*.sh certs/* -.DS_Store +**/.DS_Store diff --git a/CODEOWNERS b/CODEOWNERS index 0f8a2d3b..b7948371 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,5 +5,4 @@ # For more details, read the following article on GitHub: https://help.github.com/articles/about-codeowners/. # These are the default owners for the whole content of this repository. The default owners are automatically added as reviewers when you open a pull request, unless different owners are specified in the file. -* @eu-digital-green-certificates/dgc-gateway-members -* @ascheibal @f11h @litlfred +* @ascheibal @f11h @litlfred @tence diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md index ae39d6cc..2a3dc66b 100644 --- a/THIRD-PARTY.md +++ b/THIRD-PARTY.md @@ -11,28 +11,29 @@ ThirdParty Licenses | Dependency | License | | --- | --- | -| ch.qos.logback:logback-classic:1.4.6 | Eclipse Public License - v 1.0 GNU Lesser General Public License | -| ch.qos.logback:logback-core:1.4.6 | Eclipse Public License - v 1.0 GNU Lesser General Public License | +| ch.qos.logback:logback-classic:1.4.8 | Eclipse Public License - v 1.0 GNU Lesser General Public License | +| ch.qos.logback:logback-core:1.4.8 | Eclipse Public License - v 1.0 GNU Lesser General Public License | | com.apicatalog:titanium-json-ld:1.1.0 | Apache License, Version 2.0 | -| com.azure:azure-core:1.34.0 | The MIT License (MIT) | -| com.azure:azure-core-http-netty:1.12.7 | The MIT License (MIT) | -| com.azure:azure-identity:1.7.0 | The MIT License (MIT) | -| com.azure:azure-security-keyvault-keys:4.5.2 | The MIT License (MIT) | -| com.azure:azure-storage-blob:12.20.1 | The MIT License (MIT) | -| com.azure:azure-storage-common:12.19.1 | The MIT License (MIT) | -| com.azure:azure-storage-internal-avro:12.5.1 | The MIT License (MIT) | +| com.azure:azure-core:1.43.0 | The MIT License (MIT) | +| com.azure:azure-core-http-netty:1.13.7 | The MIT License (MIT) | +| com.azure:azure-identity:1.10.1 | The MIT License (MIT) | +| com.azure:azure-json:1.1.0 | The MIT License (MIT) | +| com.azure:azure-security-keyvault-keys:4.7.0 | The MIT License (MIT) | +| com.azure:azure-storage-blob:12.24.0 | The MIT License (MIT) | +| com.azure:azure-storage-common:12.23.0 | The MIT License (MIT) | +| com.azure:azure-storage-internal-avro:12.9.0 | The MIT License (MIT) | | com.damnhandy:handy-uri-templates:2.1.8 | The Apache Software License, Version 2.0 | | com.danubetech:key-formats-java:1.2.0 | Unknown license | | com.fasterxml:classmate:1.5.1 | Apache License, Version 2.0 | -| com.fasterxml.jackson.core:jackson-annotations:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.jackson.core:jackson-core:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.jackson.core:jackson-databind:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.jackson.module:jackson-module-parameter-names:2.14.2 | The Apache Software License, Version 2.0 | -| com.fasterxml.woodstox:woodstox-core:6.4.0 | The Apache License, Version 2.0 | +| com.fasterxml.jackson.core:jackson-annotations:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.jackson.core:jackson-core:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.jackson.core:jackson-databind:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.jackson.module:jackson-module-parameter-names:2.14.3 | The Apache Software License, Version 2.0 | +| com.fasterxml.woodstox:woodstox-core:6.5.0 | The Apache License, Version 2.0 | | com.github.everit-org.json-schema:org.everit.json.schema:1.14.2 | Apache License, Version 2.0 | | com.github.jnr:jffi:1.2.9 | The Apache Software License, Version 2.0 | | com.github.jnr:jnr-ffi:2.0.5 | The Apache Software License, Version 2.0 | @@ -48,19 +49,19 @@ ThirdParty Licenses | com.google.j2objc:j2objc-annotations:1.3 | The Apache Software License, Version 2.0 | | com.google.protobuf:protobuf-javalite:3.21.12 | BSD-3-Clause | | com.google.re2j:re2j:1.6 | Go License | -| com.h2database:h2:2.1.214 | EPL 1.0 MPL 2.0 | +| com.h2database:h2:2.2.220 | EPL 1.0 MPL 2.0 | | com.jayway.jsonpath:json-path:2.7.0 | The Apache Software License, Version 2.0 | -| com.microsoft.azure:msal4j:1.13.3 | MIT License | -| com.microsoft.azure:msal4j-persistence-extension:1.1.0 | MIT License | -| com.mysql:mysql-connector-j:8.0.32 | The GNU General Public License, v2 with Universal FOSS Exception, v1.0 | +| com.microsoft.azure:msal4j:1.13.9 | MIT License | +| com.microsoft.azure:msal4j-persistence-extension:1.2.0 | MIT License | +| com.mysql:mysql-connector-j:8.0.33 | The GNU General Public License, v2 with Universal FOSS Exception, v1.0 | | com.nimbusds:content-type:2.2 | The Apache Software License, Version 2.0 | -| com.nimbusds:lang-tag:1.6 | The Apache Software License, Version 2.0 | +| com.nimbusds:lang-tag:1.7 | The Apache Software License, Version 2.0 | | com.nimbusds:nimbus-jose-jwt:9.9 | The Apache Software License, Version 2.0 | -| com.nimbusds:oauth2-oidc-sdk:9.35 | Apache License, version 2.0 | +| com.nimbusds:oauth2-oidc-sdk:10.7.1 | Apache License, version 2.0 | | com.opencsv:opencsv:5.7.1 | Apache 2 | | com.squareup.okhttp3:okhttp:4.10.0 | The Apache Software License, Version 2.0 | | com.squareup.okio:okio-jvm:3.0.0 | The Apache Software License, Version 2.0 | -| com.sun.istack:istack-commons-runtime:4.1.1 | Eclipse Distribution License - v 1.0 | +| com.sun.istack:istack-commons-runtime:4.1.2 | Eclipse Distribution License - v 1.0 | | com.upokecenter:cbor:4.5.2 | CC0-1.0 | | com.vaadin.external.google:android-json:0.0.20131108.vaadin1 | Apache License 2.0 | | com.zaxxer:HikariCP:5.0.1 | The Apache Software License, Version 2.0 | @@ -74,39 +75,39 @@ ThirdParty Licenses | decentralized-identity:jsonld-common-java:1.0.0 | Unknown license | | info.weboftrust:ld-signatures-java:1.1.0 | Unknown license | | io.github.erdtman:java-json-canonicalization:1.1 | Apache License, Version 2.0 | -| io.github.openfeign:feign-core:12.1 | The Apache Software License, Version 2.0 | -| io.github.openfeign:feign-httpclient:12.1 | The Apache Software License, Version 2.0 | -| io.github.openfeign:feign-slf4j:12.1 | The Apache Software License, Version 2.0 | +| io.github.openfeign:feign-core:12.4 | The Apache Software License, Version 2.0 | +| io.github.openfeign:feign-httpclient:12.4 | The Apache Software License, Version 2.0 | +| io.github.openfeign:feign-slf4j:12.4 | The Apache Software License, Version 2.0 | | io.github.openfeign.form:feign-form:3.8.0 | The Apache Software License, Version 2.0 | | io.github.openfeign.form:feign-form-spring:3.8.0 | The Apache Software License, Version 2.0 | -| io.micrometer:micrometer-commons:1.10.5 | The Apache Software License, Version 2.0 | -| io.micrometer:micrometer-core:1.10.5 | The Apache Software License, Version 2.0 | -| io.micrometer:micrometer-observation:1.10.5 | The Apache Software License, Version 2.0 | -| io.micrometer:micrometer-registry-prometheus:1.10.5 | The Apache Software License, Version 2.0 | -| io.netty:netty-buffer:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-codec:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-codec-dns:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-codec-http:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-codec-http2:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-codec-socks:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-common:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-handler:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-handler-proxy:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-resolver:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-resolver-dns:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-resolver-dns-classes-macos:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-resolver-dns-native-macos:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-tcnative-boringssl-static:2.0.59.Final | The Apache Software License, Version 2.0 | -| io.netty:netty-tcnative-classes:2.0.59.Final | The Apache Software License, Version 2.0 | -| io.netty:netty-transport:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-transport-classes-epoll:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-transport-classes-kqueue:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-transport-native-epoll:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-transport-native-kqueue:4.1.90.Final | Apache License, Version 2.0 | -| io.netty:netty-transport-native-unix-common:4.1.90.Final | Apache License, Version 2.0 | -| io.projectreactor:reactor-core:3.5.4 | Apache License, Version 2.0 | -| io.projectreactor.netty:reactor-netty-core:1.1.5 | The Apache Software License, Version 2.0 | -| io.projectreactor.netty:reactor-netty-http:1.1.5 | The Apache Software License, Version 2.0 | +| io.micrometer:micrometer-commons:1.10.9 | The Apache Software License, Version 2.0 | +| io.micrometer:micrometer-core:1.10.9 | The Apache Software License, Version 2.0 | +| io.micrometer:micrometer-observation:1.10.9 | The Apache Software License, Version 2.0 | +| io.micrometer:micrometer-registry-prometheus:1.10.9 | The Apache Software License, Version 2.0 | +| io.netty:netty-buffer:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-codec:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-codec-dns:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-codec-http:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-codec-http2:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-codec-socks:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-common:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-handler:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-handler-proxy:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-resolver:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-resolver-dns:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-resolver-dns-classes-macos:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-resolver-dns-native-macos:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-tcnative-boringssl-static:2.0.61.Final | The Apache Software License, Version 2.0 | +| io.netty:netty-tcnative-classes:2.0.61.Final | The Apache Software License, Version 2.0 | +| io.netty:netty-transport:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-transport-classes-epoll:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-transport-classes-kqueue:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-transport-native-epoll:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-transport-native-kqueue:4.1.94.Final | Apache License, Version 2.0 | +| io.netty:netty-transport-native-unix-common:4.1.94.Final | Apache License, Version 2.0 | +| io.projectreactor:reactor-core:3.5.8 | Apache License, Version 2.0 | +| io.projectreactor.netty:reactor-netty-core:1.1.9 | The Apache Software License, Version 2.0 | +| io.projectreactor.netty:reactor-netty-http:1.1.9 | The Apache Software License, Version 2.0 | | io.prometheus:simpleclient:0.16.0 | The Apache Software License, Version 2.0 | | io.prometheus:simpleclient_common:0.16.0 | The Apache Software License, Version 2.0 | | io.prometheus:simpleclient_tracer_common:0.16.0 | The Apache Software License, Version 2.0 | @@ -116,7 +117,7 @@ ThirdParty Licenses | io.swagger.core.v3:swagger-annotations-jakarta:2.2.9 | Apache License 2.0 | | io.swagger.core.v3:swagger-core-jakarta:2.2.9 | Apache License 2.0 | | io.swagger.core.v3:swagger-models-jakarta:2.2.9 | Apache License 2.0 | -| jakarta.activation:jakarta.activation-api:2.1.1 | EDL 1.0 | +| jakarta.activation:jakarta.activation-api:2.1.2 | EDL 1.0 | | jakarta.annotation:jakarta.annotation-api:2.1.1 | EPL 2.0 GPL2 w/ CPE | | jakarta.inject:jakarta.inject-api:2.0.0 | The Apache Software License, Version 2.0 | | jakarta.persistence:jakarta.persistence-api:3.1.0 | Eclipse Distribution License v. 1.0 Eclipse Public License v. 2.0 | @@ -128,14 +129,14 @@ ThirdParty Licenses | joda-time:joda-time:2.10.2 | Apache 2 | | net.bytebuddy:byte-buddy:1.12.23 | Apache License, Version 2.0 | | net.bytebuddy:byte-buddy-agent:1.12.23 | Apache License, Version 2.0 | -| net.java.dev.jna:jna:5.5.0 | Apache License v2.0 LGPL, version 2.1 | +| net.java.dev.jna:jna:5.13.0 | Apache-2.0 LGPL-2.1-or-later | | net.java.dev.jna:jna-platform:5.6.0 | Apache License v2.0 LGPL, version 2.1 | | net.javacrumbs.shedlock:shedlock-core:5.2.0 | The Apache Software License, Version 2.0 | | net.javacrumbs.shedlock:shedlock-provider-jdbc-template:5.2.0 | The Apache Software License, Version 2.0 | | net.javacrumbs.shedlock:shedlock-spring:5.2.0 | The Apache Software License, Version 2.0 | | net.jcip:jcip-annotations:1.0 | Unknown license | -| net.minidev:accessors-smart:2.4.9 | The Apache Software License, Version 2.0 | -| net.minidev:json-smart:2.4.10 | The Apache Software License, Version 2.0 | +| net.minidev:accessors-smart:2.4.11 | The Apache Software License, Version 2.0 | +| net.minidev:json-smart:2.4.11 | The Apache Software License, Version 2.0 | | org.abstractj.kalium:kalium:0.8.0 | The Apache Software License, Version 2.0 | | org.antlr:antlr4-runtime:4.10.1 | The BSD License | | org.apache.commons:commons-collections4:4.4 | Apache License, Version 2.0 | @@ -145,47 +146,43 @@ ThirdParty Licenses | org.apache.httpcomponents:httpcore:4.4.16 | Apache License, Version 2.0 | | org.apache.logging.log4j:log4j-api:2.19.0 | Apache License, Version 2.0 | | org.apache.logging.log4j:log4j-to-slf4j:2.19.0 | Apache License, Version 2.0 | -| org.apache.tomcat.embed:tomcat-embed-core:10.1.7 | Apache License, Version 2.0 | -| org.apache.tomcat.embed:tomcat-embed-el:10.1.7 | Apache License, Version 2.0 | -| org.apache.tomcat.embed:tomcat-embed-websocket:10.1.7 | Apache License, Version 2.0 | +| org.apache.tomcat.embed:tomcat-embed-core:10.1.11 | Apache License, Version 2.0 | +| org.apache.tomcat.embed:tomcat-embed-el:10.1.11 | Apache License, Version 2.0 | +| org.apache.tomcat.embed:tomcat-embed-websocket:10.1.11 | Apache License, Version 2.0 | | org.apiguardian:apiguardian-api:1.1.2 | The Apache License, Version 2.0 | | org.aspectj:aspectjweaver:1.9.19 | Eclipse Public License - v 2.0 | | org.assertj:assertj-core:3.23.1 | Apache License, Version 2.0 | | org.bitcoinj:bitcoinj-core:0.16.2 | The Apache Software License, Version 2.0 | -| org.bouncycastle:bcpkix-jdk15on:1.69 | Bouncy Castle Licence | -| org.bouncycastle:bcpkix-jdk18on:1.73 | Bouncy Castle Licence | -| org.bouncycastle:bcprov-jdk15on:1.69 | Bouncy Castle Licence | -| org.bouncycastle:bcprov-jdk15to18:1.69 | Bouncy Castle Licence | -| org.bouncycastle:bcprov-jdk18on:1.73 | Bouncy Castle Licence | -| org.bouncycastle:bcutil-jdk15on:1.69 | Bouncy Castle Licence | -| org.bouncycastle:bcutil-jdk18on:1.73 | Bouncy Castle Licence | +| org.bouncycastle:bcpkix-jdk18on:1.76 | Bouncy Castle Licence | +| org.bouncycastle:bcprov-jdk18on:1.76 | Bouncy Castle Licence | +| org.bouncycastle:bcutil-jdk18on:1.76 | Bouncy Castle Licence | | org.checkerframework:checker-compat-qual:2.5.5 | GNU General Public License, version 2 (GPL2), with the classpath exception The MIT License | | org.checkerframework:checker-qual:3.5.0 | The MIT License | | org.codehaus.woodstox:stax2-api:4.2.1 | The BSD License | -| org.eclipse.angus:angus-activation:2.0.0 | EDL 1.0 | +| org.eclipse.angus:angus-activation:2.0.1 | EDL 1.0 | | org.glassfish:jakarta.json:2.0.0 | Eclipse Public License 2.0 GNU General Public License, version 2 with the GNU Classpath Exception | -| org.glassfish.jaxb:jaxb-core:4.0.2 | Eclipse Distribution License - v 1.0 | -| org.glassfish.jaxb:jaxb-runtime:4.0.2 | Eclipse Distribution License - v 1.0 | -| org.glassfish.jaxb:txw2:4.0.2 | Eclipse Distribution License - v 1.0 | +| org.glassfish.jaxb:jaxb-core:4.0.3 | Eclipse Distribution License - v 1.0 | +| org.glassfish.jaxb:jaxb-runtime:4.0.3 | Eclipse Distribution License - v 1.0 | +| org.glassfish.jaxb:txw2:4.0.3 | Eclipse Distribution License - v 1.0 | | org.hamcrest:hamcrest:2.2 | BSD License 3 | | org.hdrhistogram:HdrHistogram:2.1.12 | BSD-2-Clause Public Domain, per Creative Commons CC0 | | org.hibernate.common:hibernate-commons-annotations:6.0.6.Final | GNU Library General Public License v2.1 or later | | org.hibernate.orm:hibernate-core:6.1.7.Final | GNU Library General Public License v2.1 or later | -| org.hibernate.validator:hibernate-validator:8.0.0.Final | Apache License 2.0 | +| org.hibernate.validator:hibernate-validator:8.0.1.Final | Apache License 2.0 | | org.jboss:jandex:2.4.2.Final | Apache License, Version 2.0 | -| org.jboss.logging:jboss-logging:3.5.0.Final | Apache License, version 2.0 | +| org.jboss.logging:jboss-logging:3.5.3.Final | Apache License 2.0 | | org.jetbrains:annotations:13.0 | The Apache Software License, Version 2.0 | | org.jetbrains.kotlin:kotlin-stdlib:1.7.22 | The Apache License, Version 2.0 | | org.jetbrains.kotlin:kotlin-stdlib-common:1.7.22 | The Apache License, Version 2.0 | | org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.22 | The Apache License, Version 2.0 | | org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.22 | The Apache License, Version 2.0 | | org.json:json:20230227 | Public Domain | -| org.junit.jupiter:junit-jupiter:5.9.2 | Eclipse Public License v2.0 | -| org.junit.jupiter:junit-jupiter-api:5.9.2 | Eclipse Public License v2.0 | -| org.junit.jupiter:junit-jupiter-engine:5.9.2 | Eclipse Public License v2.0 | -| org.junit.jupiter:junit-jupiter-params:5.9.2 | Eclipse Public License v2.0 | -| org.junit.platform:junit-platform-commons:1.9.2 | Eclipse Public License v2.0 | -| org.junit.platform:junit-platform-engine:1.9.2 | Eclipse Public License v2.0 | +| org.junit.jupiter:junit-jupiter:5.9.3 | Eclipse Public License v2.0 | +| org.junit.jupiter:junit-jupiter-api:5.9.3 | Eclipse Public License v2.0 | +| org.junit.jupiter:junit-jupiter-engine:5.9.3 | Eclipse Public License v2.0 | +| org.junit.jupiter:junit-jupiter-params:5.9.3 | Eclipse Public License v2.0 | +| org.junit.platform:junit-platform-commons:1.9.3 | Eclipse Public License v2.0 | +| org.junit.platform:junit-platform-engine:1.9.3 | Eclipse Public License v2.0 | | org.latencyutils:LatencyUtils:2.0.3 | Public Domain, per Creative Commons CC0 | | org.liquibase:liquibase-core:4.17.2 | Apache License, Version 2.0 | | org.mapstruct:mapstruct:1.5.5.Final | The Apache Software License, Version 2.0 | @@ -199,7 +196,7 @@ ThirdParty Licenses | org.ow2.asm:asm-tree:5.0.3 | BSD | | org.ow2.asm:asm-util:5.0.3 | BSD | | org.postgresql:postgresql:42.5.4 | BSD-2-Clause | -| org.projectlombok:lombok:1.18.26 | The MIT License | +| org.projectlombok:lombok:1.18.28 | The MIT License | | org.reactivestreams:reactive-streams:1.0.4 | MIT-0 | | org.semver4j:semver4j:4.3.0 | The MIT License | | org.skyscreamer:jsonassert:1.5.1 | The Apache Software License, Version 2.0 | @@ -208,49 +205,49 @@ ThirdParty Licenses | org.springdoc:springdoc-openapi-starter-common:2.1.0 | The Apache License, Version 2.0 | | org.springdoc:springdoc-openapi-starter-webmvc-api:2.1.0 | The Apache License, Version 2.0 | | org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0 | The Apache License, Version 2.0 | -| org.springframework:spring-aop:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-aspects:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-beans:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-context:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-core:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-expression:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-jcl:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-jdbc:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-orm:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-test:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-tx:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-web:6.0.7 | Apache License, Version 2.0 | -| org.springframework:spring-webmvc:6.0.7 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-actuator:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-actuator-autoconfigure:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-autoconfigure:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-actuator:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-aop:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-data-jpa:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-jdbc:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-json:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-logging:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-test:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-tomcat:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-validation:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-starter-web:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-test:3.0.5 | Apache License, Version 2.0 | -| org.springframework.boot:spring-boot-test-autoconfigure:3.0.5 | Apache License, Version 2.0 | -| org.springframework.cloud:spring-cloud-commons:4.0.2 | Apache License, Version 2.0 | -| org.springframework.cloud:spring-cloud-context:4.0.2 | Apache License, Version 2.0 | -| org.springframework.cloud:spring-cloud-openfeign-core:4.0.2 | Apache License, Version 2.0 | -| org.springframework.cloud:spring-cloud-starter:4.0.2 | Apache License, Version 2.0 | -| org.springframework.cloud:spring-cloud-starter-openfeign:4.0.2 | Apache License, Version 2.0 | -| org.springframework.data:spring-data-commons:3.0.4 | Apache License, Version 2.0 | -| org.springframework.data:spring-data-jpa:3.0.4 | Apache License, Version 2.0 | -| org.springframework.security:spring-security-config:6.0.2 | Apache License, Version 2.0 | -| org.springframework.security:spring-security-core:6.0.2 | Apache License, Version 2.0 | -| org.springframework.security:spring-security-crypto:6.0.2 | Apache License, Version 2.0 | -| org.springframework.security:spring-security-rsa:1.0.11.RELEASE | Apache 2.0 | -| org.springframework.security:spring-security-test:6.0.2 | Apache License, Version 2.0 | -| org.springframework.security:spring-security-web:6.0.2 | Apache License, Version 2.0 | +| org.springframework:spring-aop:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-aspects:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-beans:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-context:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-core:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-expression:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-jcl:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-jdbc:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-orm:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-test:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-tx:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-web:6.0.11 | Apache License, Version 2.0 | +| org.springframework:spring-webmvc:6.0.11 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-actuator:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-actuator-autoconfigure:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-autoconfigure:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-actuator:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-aop:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-data-jpa:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-jdbc:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-json:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-logging:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-test:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-tomcat:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-validation:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-starter-web:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-test:3.0.9 | Apache License, Version 2.0 | +| org.springframework.boot:spring-boot-test-autoconfigure:3.0.9 | Apache License, Version 2.0 | +| org.springframework.cloud:spring-cloud-commons:4.0.4 | Apache License, Version 2.0 | +| org.springframework.cloud:spring-cloud-context:4.0.4 | Apache License, Version 2.0 | +| org.springframework.cloud:spring-cloud-openfeign-core:4.0.4 | Apache License, Version 2.0 | +| org.springframework.cloud:spring-cloud-starter:4.0.4 | Apache License, Version 2.0 | +| org.springframework.cloud:spring-cloud-starter-openfeign:4.0.4 | Apache License, Version 2.0 | +| org.springframework.data:spring-data-commons:3.0.8 | Apache License, Version 2.0 | +| org.springframework.data:spring-data-jpa:3.0.8 | Apache License, Version 2.0 | +| org.springframework.security:spring-security-config:6.0.5 | Apache License, Version 2.0 | +| org.springframework.security:spring-security-core:6.0.5 | Apache License, Version 2.0 | +| org.springframework.security:spring-security-crypto:6.0.5 | Apache License, Version 2.0 | +| org.springframework.security:spring-security-rsa:1.0.12.RELEASE | Apache 2.0 | +| org.springframework.security:spring-security-test:6.0.5 | Apache License, Version 2.0 | +| org.springframework.security:spring-security-web:6.0.5 | Apache License, Version 2.0 | | org.webjars:swagger-ui:4.18.2 | Apache 2.0 | | org.xmlunit:xmlunit-core:2.9.1 | The Apache Software License, Version 2.0 | | org.yaml:snakeyaml:1.33 | Apache License, Version 2.0 | diff --git a/docker-compose.yml b/docker-compose.yml index 0024c7a9..49d6ccd6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,21 @@ version: '3' services: - mysql: - image: mysql/mysql-server:5.7 + postgres: + image: postgres ports: - - 3306:3306 + - 5432:5432 environment: - - MYSQL_DATABASE=dgc - - MYSQL_ROOT_PASSWORD=admin # do not use this for production deployments - - MYSQL_USER=dgc_adm - - MYSQL_PASSWORD=admin # do not use this for production deployments + - POSTGRES_PASSWORD=admin # do not use this for production deployments + - PGPASSWORD=admin # do not use this for production deployments + - POSTGRES_USER=postgres + - POSTGRES_DB=postgres networks: persistence: ddcc-gateway: build: . - image: world-health-organization/ddcc-gateway + image: smarttrustnetworkgateway:latest volumes: - ./certs:/ec/prod/app/san/dgc - ./logs:/logs @@ -23,9 +23,12 @@ services: - 8080:8080 environment: - SERVER_PORT=8080 - - SPRING_PROFILES_ACTIVE=mysql,docker - - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/dgc - - SPRING_DATASOURCE_USERNAME=dgc_adm + - SPRING_PROFILES_ACTIVE=log2console,local + - SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/postgres + - SPRING_DATASOURCE_DRIVERCLASSNAME=org.postgresql.Driver + - SPRING_DATASOURCE_JNDI_NAME=false + - SPRING_JPA_DATABASEPLATFORM=org.hibernate.dialect.PostgreSQLDialect + - SPRING_DATASOURCE_USERNAME=postgres - SPRING_DATASOURCE_PASSWORD=admin # do not use this for production deployments - DGC_TRUSTANCHOR_KEYSTOREPATH=/ec/prod/app/san/dgc/ta.jks - DGC_TRUSTANCHOR_KEYSTOREPASS=dgcg-p4ssw0rd # do not use this for production deployments @@ -33,7 +36,7 @@ services: - DGC_FEDERATION_KEYSTOREPATH=/ec/prod/app/san/dgc/ta.jks #TODO: change to federation.jks - DGC_FEDERATION_KEYSTOREPASSWORD=dgcg-p4ssw0rd # do not use this for production deployments depends_on: - - mysql + - postgres networks: backend: persistence: diff --git a/owasp/suppressions.xml b/owasp/suppressions.xml index 70fff6e0..01e8848c 100644 --- a/owasp/suppressions.xml +++ b/owasp/suppressions.xml @@ -44,4 +44,9 @@ CVE-2023-1370 CVE-2023-24998 + + No Fix available + CVE-2023-36414 + CVE-2023-36415 + diff --git a/src/main/java/eu/europa/ec/dgc/gateway/config/DgcConfigProperties.java b/src/main/java/eu/europa/ec/dgc/gateway/config/DgcConfigProperties.java index 5c650986..65c2574b 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/config/DgcConfigProperties.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/config/DgcConfigProperties.java @@ -52,6 +52,8 @@ public class DgcConfigProperties { private CloudmersiveConfig cloudmersive = new CloudmersiveConfig(); + private CountryCodeMap countryCodeMap = new CountryCodeMap(); + @Getter @Setter public static class DidConfig { @@ -170,4 +172,10 @@ public static class Federation { public static class SignerInformation { private int deleteThreshold = 14; } + + @Getter + @Setter + public static class CountryCodeMap { + private Map virtualCountries = new HashMap<>(); + } } diff --git a/src/main/java/eu/europa/ec/dgc/gateway/entity/FederatedEntity.java b/src/main/java/eu/europa/ec/dgc/gateway/entity/FederatedEntity.java index dac491da..b433d178 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/entity/FederatedEntity.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/entity/FederatedEntity.java @@ -41,7 +41,7 @@ public abstract class FederatedEntity { @JoinColumn(name = "source_gateway_id", referencedColumnName = "gateway_id") private FederationGatewayEntity sourceGateway; - @Column(name = "domain", columnDefinition = "varchar(10) DEFAULT 'DCC'") + @Column(name = "domain", columnDefinition = "varchar(32) DEFAULT 'DCC'") String domain = "DCC"; @Column(name = "version", columnDefinition = "int default 1", nullable = false) diff --git a/src/main/java/eu/europa/ec/dgc/gateway/entity/RevocationBatchEntity.java b/src/main/java/eu/europa/ec/dgc/gateway/entity/RevocationBatchEntity.java index b3fca6c3..37f34c7f 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/entity/RevocationBatchEntity.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/entity/RevocationBatchEntity.java @@ -28,13 +28,14 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Index; -import jakarta.persistence.Lob; import jakarta.persistence.Table; import java.time.ZonedDateTime; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.hibernate.annotations.JdbcType; +import org.hibernate.type.descriptor.jdbc.LongVarcharJdbcType; @Getter @Setter @@ -97,7 +98,7 @@ public class RevocationBatchEntity { * The Signed CMS with the batch. */ @Column(name = "signed_batch", length = 1_024_000) - @Lob + @JdbcType(LongVarcharJdbcType.class) private String signedBatch; /** diff --git a/src/main/java/eu/europa/ec/dgc/gateway/entity/ValuesetEntity.java b/src/main/java/eu/europa/ec/dgc/gateway/entity/ValuesetEntity.java index 3a506fa8..00f4c54b 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/entity/ValuesetEntity.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/entity/ValuesetEntity.java @@ -23,12 +23,14 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; -import jakarta.persistence.Lob; import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.hibernate.annotations.JdbcType; +import org.hibernate.type.descriptor.jdbc.LongVarcharJdbcType; + @Getter @Setter @@ -45,8 +47,8 @@ public class ValuesetEntity { /** * Signature of the TrustAnchor. */ - @Column(name = "json", nullable = false, length = 1024000) - @Lob + @Column(name = "json", nullable = false, length = 1_024_000) + @JdbcType(LongVarcharJdbcType.class) String json; } diff --git a/src/main/java/eu/europa/ec/dgc/gateway/model/TrustedCertificateTrustList.java b/src/main/java/eu/europa/ec/dgc/gateway/model/TrustedCertificateTrustList.java index 15d4cac2..06adb56b 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/model/TrustedCertificateTrustList.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/model/TrustedCertificateTrustList.java @@ -20,6 +20,7 @@ package eu.europa.ec.dgc.gateway.model; +import java.security.cert.X509Certificate; import java.time.ZonedDateTime; import lombok.AllArgsConstructor; import lombok.Data; @@ -52,4 +53,6 @@ public class TrustedCertificateTrustList { private Integer version; + private X509Certificate parsedCertificate; + } diff --git a/src/main/java/eu/europa/ec/dgc/gateway/repository/SignerInformationRepository.java b/src/main/java/eu/europa/ec/dgc/gateway/repository/SignerInformationRepository.java index a974da9b..7f0c5a46 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/repository/SignerInformationRepository.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/repository/SignerInformationRepository.java @@ -30,8 +30,6 @@ public interface SignerInformationRepository extends JpaRepository { - List getAllBySourceGatewayIsNullAndDomainIs(String domain); - @Query("SELECT s FROM SignerInformationEntity s WHERE " + "(:ignoreGroup = true OR s.certificateType IN (:group)) AND " + "(:ignoreCountry = true OR s.country IN (:country)) AND " diff --git a/src/main/java/eu/europa/ec/dgc/gateway/repository/TrustedPartyRepository.java b/src/main/java/eu/europa/ec/dgc/gateway/repository/TrustedPartyRepository.java index 00159ed3..9e2439c1 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/repository/TrustedPartyRepository.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/repository/TrustedPartyRepository.java @@ -30,7 +30,8 @@ public interface TrustedPartyRepository extends JpaRepository { - List getBySourceGatewayIsNullAndDomainIs(String domain); + List getBySourceGatewayIsNullAndDomainIsAndCertificateTypeIsIn( + String domain, List types); List getByCountryAndCertificateType(String country, TrustedPartyEntity.CertificateType type); diff --git a/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListDto.java b/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListDto.java index acdb1106..db3661bf 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListDto.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListDto.java @@ -21,10 +21,12 @@ package eu.europa.ec.dgc.gateway.restapi.dto.did; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; import java.util.List; import lombok.Data; @Data +@JsonPropertyOrder({"@context", "id", "controller", "verificationMethod"}) public class DidTrustListDto { @JsonProperty("@context") diff --git a/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListEntryDto.java b/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListEntryDto.java index 12e97d65..25deb323 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListEntryDto.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/restapi/dto/did/DidTrustListEntryDto.java @@ -21,9 +21,16 @@ package eu.europa.ec.dgc.gateway.restapi.dto.did; import com.fasterxml.jackson.annotation.JsonProperty; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; +import java.util.Base64; import java.util.List; import lombok.Data; -import lombok.experimental.SuperBuilder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.bouncycastle.jce.spec.ECNamedCurveSpec; @Data public class DidTrustListEntryDto { @@ -36,18 +43,24 @@ public class DidTrustListEntryDto { private PublicKeyJwk publicKeyJwk; - @Data - @SuperBuilder - private abstract static class PublicKeyJwk { + @NoArgsConstructor + @Setter + @Getter + public abstract static class PublicKeyJwk { @JsonProperty("kty") private String keyType; @JsonProperty("x5c") private List encodedX509Certificates; + + private PublicKeyJwk(String keyType, List encodedX509Certificates) { + this.keyType = keyType; + this.encodedX509Certificates = new ArrayList<>(encodedX509Certificates); + } } - @Data - @SuperBuilder + @Getter + @Setter public static class EcPublicKeyJwk extends PublicKeyJwk { @JsonProperty("crv") @@ -58,6 +71,51 @@ public static class EcPublicKeyJwk extends PublicKeyJwk { @JsonProperty("y") private String valueY; + + /** + * Instantiate EC PublicKey JWK Class. + * + * @param ecPublicKey EC Public Key that should be wrapped. + * @param base64EncodedCertificates List of Base64 encoded Certificates assigned to provided Public Key. + * They will be added within x5c property of JWK. + */ + public EcPublicKeyJwk(ECPublicKey ecPublicKey, List base64EncodedCertificates) { + super("EC", base64EncodedCertificates); + valueX = Base64.getEncoder().encodeToString(ecPublicKey.getW().getAffineX().toByteArray()); + valueY = Base64.getEncoder().encodeToString(ecPublicKey.getW().getAffineY().toByteArray()); + + ECNamedCurveSpec curveSpec = (ECNamedCurveSpec) ecPublicKey.getParams(); + switch (curveSpec.getName()) { + case "prime256v1" -> curve = "P-256"; + case "prime384v1" -> curve = "P-384"; + case "prime521v1" -> curve = "P-521"; + default -> curve = "UNKNOWN CURVE"; + } + } + } + + @Getter + @Setter + public static class RsaPublicKeyJwk extends PublicKeyJwk { + + @JsonProperty("e") + private String valueE; + + @JsonProperty("n") + private String valueN; + + /** + * Instantiate RSA PublicKey JWK Class. + * + * @param rsaPublicKey RSA Public Key that should be wrapped. + * @param base64EncodedCertificates List of Base64 encoded Certificates assigned to provided Public Key. + * They will be added within x5c property of JWK. + */ + public RsaPublicKeyJwk(RSAPublicKey rsaPublicKey, List base64EncodedCertificates) { + super("RSA", base64EncodedCertificates); + valueN = Base64.getEncoder().encodeToString(rsaPublicKey.getModulus().toByteArray()); + valueE = Base64.getEncoder().encodeToString(rsaPublicKey.getPublicExponent().toByteArray()); + } } } diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/SignerInformationService.java b/src/main/java/eu/europa/ec/dgc/gateway/service/SignerInformationService.java index 44faee95..11956bf9 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/SignerInformationService.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/SignerInformationService.java @@ -70,24 +70,15 @@ public class SignerInformationService { private static final String MDC_PROP_UPLOAD_CERT_THUMBPRINT = "uploadCertThumbprint"; private static final String MDC_PROP_CSCA_CERT_THUMBPRINT = "cscaCertThumbprint"; - /** - * Method to query persistence layer for all stored non federated SignerInformation. - * - * @return List of SignerInformation - */ - public List getNonFederatedSignerInformation() { - return signerInformationRepository.getAllBySourceGatewayIsNullAndDomainIs("DCC"); - } /** - * Method to query persistence layer for SignerInformation filtered by Type. + * Method to query persistence layer for SignerInformation filtered by Type = DSC. * - * @param type type to filter for * @return List of SignerInformation */ - public List getNonFederatedSignerInformation( - SignerInformationEntity.CertificateType type) { - return signerInformationRepository.getByCertificateTypeAndSourceGatewayIsNullAndDomainIs(type, "DCC"); + public List getNonFederatedEuDscSignerInformation() { + return signerInformationRepository.getByCertificateTypeAndSourceGatewayIsNullAndDomainIs( + SignerInformationEntity.CertificateType.DSC, "DCC"); } /** diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/TrustListService.java b/src/main/java/eu/europa/ec/dgc/gateway/service/TrustListService.java index 7b823da2..023a5465 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/TrustListService.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/TrustListService.java @@ -53,8 +53,8 @@ public class TrustListService { */ public List getTrustList() { return mergeAndConvert( - trustedPartyService.getNonFederatedTrustedParties(), - signerInformationService.getNonFederatedSignerInformation() + trustedPartyService.getNonFederatedEuDscTrustedParties(), + signerInformationService.getNonFederatedEuDscSignerInformation() ); } @@ -68,11 +68,11 @@ public List getTrustList(TrustListType type) { if (type == TrustListType.DSC) { return mergeAndConvert( Collections.emptyList(), - signerInformationService.getNonFederatedSignerInformation(SignerInformationEntity.CertificateType.DSC) + signerInformationService.getNonFederatedEuDscSignerInformation() ); } else { return mergeAndConvert( - trustedPartyService.getNonFederatedTrustedParties(map(type)), + trustedPartyService.getNonFederatedEuDscTrustedParties(map(type)), Collections.emptyList() ); } @@ -156,7 +156,8 @@ private TrustedCertificateTrustList convertTrustedCertificate(TrustedPartyEntity ? trustedPartyEntity.getSourceGateway().getGatewayId() : null, trustedPartyEntity.getUuid(), trustedPartyEntity.getDomain(), - trustedPartyEntity.getVersion() + trustedPartyEntity.getVersion(), + trustedPartyService.getX509CertificateFromEntity(trustedPartyEntity) ); } @@ -174,7 +175,8 @@ private TrustedCertificateTrustList convertTrustedCertificate(SignerInformationE ? signerInformationEntity.getSourceGateway().getGatewayId() : null, signerInformationEntity.getUuid(), signerInformationEntity.getDomain(), - signerInformationEntity.getVersion() + signerInformationEntity.getVersion(), + signerInformationService.getX509CertificateFromEntity(signerInformationEntity) ); } diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedIssuerService.java b/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedIssuerService.java index 737be48c..a2d9e180 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedIssuerService.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedIssuerService.java @@ -162,7 +162,8 @@ private boolean validateTrustedIssuerIntegrity(TrustedIssuerEntity trustedIssuer // verify signature SignedStringMessageParser parser = new SignedStringMessageParser( trustedIssuerEntity.getSignature(), - Base64.getEncoder().encodeToString(getHashData(trustedIssuerEntity).getBytes(StandardCharsets.UTF_8))); + Base64.getEncoder().encodeToString( + getHashData(trustedIssuerEntity).getBytes(StandardCharsets.UTF_8))); if (parser.getParserState() != SignedMessageParser.ParserState.SUCCESS) { DgcMdc.put(MDC_PROP_PARSER_STATE, parser.getParserState().name()); @@ -227,12 +228,11 @@ public TrustedIssuerEntity addFederatedTrustedIssuer(String country, return trustedIssuerEntity; } - private String getHashData(TrustedIssuerEntity entity) { - return entity.getUuid() + HASH_SEPARATOR - + entity.getCountry() + HASH_SEPARATOR - + entity.getName() + HASH_SEPARATOR - + entity.getUrl() + HASH_SEPARATOR - + entity.getUrlType().name() + HASH_SEPARATOR; + return entity.getCountry() + HASH_SEPARATOR + + entity.getName() + HASH_SEPARATOR + + entity.getUrl() + HASH_SEPARATOR + + entity.getUrlType().name(); } } + diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedPartyService.java b/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedPartyService.java index 609b9562..9821e176 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedPartyService.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/TrustedPartyService.java @@ -65,9 +65,11 @@ public class TrustedPartyService { * * @return List holding the found certificates. */ - public List getNonFederatedTrustedParties() { + public List getNonFederatedEuDscTrustedParties() { - return trustedPartyRepository.getBySourceGatewayIsNullAndDomainIs("DCC") + return trustedPartyRepository.getBySourceGatewayIsNullAndDomainIsAndCertificateTypeIsIn("DCC", + List.of(TrustedPartyEntity.CertificateType.UPLOAD, TrustedPartyEntity.CertificateType.AUTHENTICATION, + TrustedPartyEntity.CertificateType.CSCA)) .stream() .filter(this::validateCertificateIntegrity) .collect(Collectors.toList()); @@ -79,7 +81,7 @@ public List getNonFederatedTrustedParties() { * @param type type to filter for. * @return List holding the found certificates. */ - public List getNonFederatedTrustedParties(TrustedPartyEntity.CertificateType type) { + public List getNonFederatedEuDscTrustedParties(TrustedPartyEntity.CertificateType type) { return trustedPartyRepository.getByCertificateTypeAndSourceGatewayIsNullAndDomainIs(type, "DCC") .stream() diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/did/AzureDidUploader.java b/src/main/java/eu/europa/ec/dgc/gateway/service/did/AzureDidUploader.java index 47507e7c..393a89ca 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/did/AzureDidUploader.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/did/AzureDidUploader.java @@ -32,6 +32,7 @@ import com.azure.storage.blob.models.BlobHttpHeaders; import eu.europa.ec.dgc.gateway.config.DgcConfigProperties; import java.net.InetSocketAddress; +import java.text.MessageFormat; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.http.MediaType; @@ -42,7 +43,7 @@ @Slf4j public class AzureDidUploader implements DidUploader { - private final BlobClient blobClient; + private final BlobServiceClient blobServiceClient; private final DgcConfigProperties dgcConfigProperties; @@ -64,7 +65,7 @@ public AzureDidUploader(DgcConfigProperties dgcConfigProperties) { HttpClient httpClient = HttpClient.createDefault(httpClientOptions); - BlobServiceClient blobServiceClient = new BlobServiceClientBuilder() + blobServiceClient = new BlobServiceClientBuilder() .httpClient(httpClient) .endpoint(dgcConfigProperties.getDid().getAzure().getBlobEndpoint()) .credential(new ClientSecretCredentialBuilder() @@ -75,10 +76,24 @@ public AzureDidUploader(DgcConfigProperties dgcConfigProperties) { .build()) .buildClient(); - BlobContainerClient blobContainerClient = blobServiceClient.getBlobContainerClient( - dgcConfigProperties.getDid().getAzure().getBlobContainer()); + } - blobClient = blobContainerClient.getBlobClient(dgcConfigProperties.getDid().getAzure().getBlobName()); + /** + * Setup container specific BlobClient. + * @param subContainer the name of the container (will be used in lowercase) + */ + public BlobClient getBlobContainerClientForBlobContainer(String subContainer) { + BlobContainerClient blobContainerClient; + if (subContainer == null) { + blobContainerClient = blobServiceClient.getBlobContainerClient( + dgcConfigProperties.getDid().getAzure().getBlobContainer()); + } else { + blobContainerClient = blobServiceClient.getBlobContainerClient( + MessageFormat.format("{0}/{1}", + dgcConfigProperties.getDid().getAzure().getBlobContainer(), + subContainer.toLowerCase())); + } + return blobContainerClient.getBlobClient(dgcConfigProperties.getDid().getAzure().getBlobName()); } @Override @@ -88,6 +103,20 @@ public void uploadDid(byte[] content) { dgcConfigProperties.getDid().getAzure().getBlobContainer(), dgcConfigProperties.getDid().getAzure().getBlobName()); + BlobClient blobClient = getBlobContainerClientForBlobContainer(null); + blobClient.upload(BinaryData.fromBytes(content), true); + blobClient.setHttpHeaders(new BlobHttpHeaders().setContentType(MediaType.APPLICATION_JSON_VALUE)); + log.info("Upload successful"); + } + + @Override + public void uploadDid(String subContainer, byte[] content) { + log.info("Uploading {} bytes as {}{}/{} to Azure BLOB Storage", content.length, + dgcConfigProperties.getDid().getAzure().getBlobEndpoint(), + dgcConfigProperties.getDid().getAzure().getBlobContainer(), + dgcConfigProperties.getDid().getAzure().getBlobName()); + + BlobClient blobClient = getBlobContainerClientForBlobContainer(subContainer); blobClient.upload(BinaryData.fromBytes(content), true); blobClient.setHttpHeaders(new BlobHttpHeaders().setContentType(MediaType.APPLICATION_JSON_VALUE)); log.info("Upload successful"); diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidTrustListService.java b/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidTrustListService.java index 8dc7b3e2..ef793993 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidTrustListService.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidTrustListService.java @@ -27,9 +27,10 @@ import eu.europa.ec.dgc.gateway.entity.SignerInformationEntity; import eu.europa.ec.dgc.gateway.entity.TrustedIssuerEntity; import eu.europa.ec.dgc.gateway.entity.TrustedPartyEntity; +import eu.europa.ec.dgc.gateway.model.TrustedCertificateTrustList; import eu.europa.ec.dgc.gateway.restapi.dto.did.DidTrustListDto; import eu.europa.ec.dgc.gateway.restapi.dto.did.DidTrustListEntryDto; -import eu.europa.ec.dgc.gateway.service.SignerInformationService; +import eu.europa.ec.dgc.gateway.service.TrustListService; import eu.europa.ec.dgc.gateway.service.TrustedIssuerService; import eu.europa.ec.dgc.gateway.service.TrustedPartyService; import foundation.identity.jsonld.ConfigurableDocumentLoader; @@ -37,41 +38,50 @@ import info.weboftrust.ldsignatures.jsonld.LDSecurityKeywords; import info.weboftrust.ldsignatures.signer.JsonWebSignature2020LdSigner; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.URI; +import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.security.cert.X509Certificate; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.Base64; import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.MissingResourceException; import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; -import org.bouncycastle.jce.spec.ECNamedCurveSpec; +import org.jetbrains.annotations.NotNull; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; + @Slf4j @Service @RequiredArgsConstructor @ConditionalOnProperty("dgc.did.enableDidGeneration") public class DidTrustListService { + private static final String SEPARATOR_COLON = ":"; + + private static final String SEPARATOR_FRAGMENT = "#"; + private static final List DID_CONTEXTS = List.of( "https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/jws-2020/v1"); - private final TrustedPartyService trustedPartyService; - - private final SignerInformationService signerInformationService; - private final TrustedIssuerService trustedIssuerService; + private final TrustListService trustListService; + private final DgcConfigProperties configProperties; private final ByteSigner byteSigner; @@ -80,15 +90,17 @@ public class DidTrustListService { private final ObjectMapper objectMapper; + private final TrustedPartyService trustedPartyService; + /** * Create and upload DID Document holding Uploaded DSC and Trusted Issuer. */ - @Scheduled(cron = "0 0 * * * *") + @Scheduled(cron = "${dgc.trustlist.cron}") @SchedulerLock(name = "didTrustListGenerator") public void job() { String trustList; try { - trustList = generateTrustList(); + trustList = generateTrustList(null); } catch (Exception e) { log.error("Failed to generate DID-TrustList: {}", e.getMessage()); return; @@ -100,76 +112,101 @@ public void job() { log.error("Failed to Upload DID-TrustList: {}", e.getMessage()); return; } + + List countries = trustedPartyService.getCountryList(); + + for (String country : countries) { + String countryTrustList = null; + List countryAsList = List.of(country); + String countryAsSubcontainer = getCountryAsLowerCaseAlpha3(country); + if (countryAsSubcontainer != null) { + try { + countryTrustList = generateTrustList(countryAsList); + } catch (Exception e) { + log.error("Failed to generate DID-TrustList for country {} : {}", country, e.getMessage()); + continue; + } + + try { + didUploader.uploadDid(countryAsSubcontainer, countryTrustList.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("Failed to Upload DID-TrustList for country {} : {}", country, e.getMessage()); + } + } + } + log.info("Finished DID Export Process"); } - private String generateTrustList() throws Exception { + private String getCountryAsLowerCaseAlpha3(String country) { + if (country == null || country.length() != 2 && country.length() != 3) { + return null; + } else if (country.length() == 3) { + return country.toLowerCase(); + } + + return configProperties.getCountryCodeMap().getVirtualCountries() + .compute(country, (alpha2, alpha3) -> { + if (alpha3 != null) { + return alpha3.toLowerCase(); + } + + try { + return new Locale("en", alpha2).getISO3Country().toLowerCase(); + } catch (MissingResourceException e) { + log.error("Country Code to alpha 3 conversion issue for country {} : {}", + country, e.getMessage()); + return null; + } + }); + } + + private String generateTrustList(List countries) throws Exception { DidTrustListDto trustList = new DidTrustListDto(); trustList.setContext(DID_CONTEXTS); trustList.setId(configProperties.getDid().getDidId()); trustList.setController(configProperties.getDid().getDidController()); trustList.setVerificationMethod(new ArrayList<>()); + if (countries != null && !countries.isEmpty()) { + trustList.setId(configProperties.getDid().getDidId() + + SEPARATOR_COLON + + getCountryAsLowerCaseAlpha3(countries.get(0))); + trustList.setController(configProperties.getDid().getDidController() + + SEPARATOR_COLON + + getCountryAsLowerCaseAlpha3(countries.get(0))); + } // Add DSC - List certs = signerInformationService.getSignerInformation( - null, null, null, configProperties.getDid().getIncludeFederated()); - - for (SignerInformationEntity cert : certs) { - DidTrustListEntryDto.EcPublicKeyJwk.EcPublicKeyJwkBuilder jwkBuilder = - DidTrustListEntryDto.EcPublicKeyJwk.builder(); - - X509Certificate x509 = signerInformationService.getX509CertificateFromEntity(cert); - + List certs = trustListService.getTrustedCertificateTrustList( + SignerInformationEntity.CertificateType.stringValues(), + countries, + null, + configProperties.getDid().getIncludeFederated() + ); - if (x509.getPublicKey() instanceof ECPublicKey publicKey) { + for (TrustedCertificateTrustList cert : certs) { - jwkBuilder.valueX(Base64.getEncoder().encodeToString(publicKey.getW().getAffineX().toByteArray())); - jwkBuilder.valueY(Base64.getEncoder().encodeToString(publicKey.getW().getAffineY().toByteArray())); + PublicKey publicKey = cert.getParsedCertificate().getPublicKey(); - ECNamedCurveSpec curveSpec = (ECNamedCurveSpec) publicKey.getParams(); - if (curveSpec.getName().equals("prime256v1")) { - jwkBuilder.curve("P-256"); - } else if (curveSpec.getName().equals("prime384v1")) { - jwkBuilder.curve("P-384"); - } else if (curveSpec.getName().equals("prime521v1")) { - jwkBuilder.curve("P-521"); - } - - jwkBuilder.keyType("EC"); - jwkBuilder.encodedX509Certificates(new ArrayList<>(List.of(cert.getRawData()))); - DidTrustListEntryDto.EcPublicKeyJwk jwk = jwkBuilder.build(); - - Optional csca = - trustedPartyService.getCertificate( - cert.getCountry(), TrustedPartyEntity.CertificateType.CSCA).stream() - .map(trustedPartyService::getX509CertificateFromEntity) - .filter(tp -> tp.getSubjectX500Principal().equals(x509.getIssuerX500Principal())) - .findFirst(); - - if (csca.isPresent()) { - jwk.getEncodedX509Certificates().add(Base64.getEncoder().encodeToString(csca.get().getEncoded())); - } + if (publicKey instanceof RSAPublicKey rsaPublicKey) { + addTrustListEntry(trustList, cert, + new DidTrustListEntryDto.RsaPublicKeyJwk(rsaPublicKey, List.of(cert.getCertificate()))); - DidTrustListEntryDto trustListEntry = new DidTrustListEntryDto(); - trustListEntry.setType("JsonWebKey2020"); - trustListEntry.setId(configProperties.getDid().getTrustListIdPrefix() + cert.getKid()); - trustListEntry.setController(configProperties.getDid().getTrustListControllerPrefix()); - trustListEntry.setPublicKeyJwk(jwk); - - trustList.getVerificationMethod().add(trustListEntry); + } else if (publicKey instanceof ECPublicKey ecPublicKey) { + addTrustListEntry(trustList, cert, + new DidTrustListEntryDto.EcPublicKeyJwk(ecPublicKey, List.of(cert.getCertificate()))); } else { - log.error("Public Key is not EC Public Key for cert {} of country {}", - cert.getThumbprint(), - cert.getCountry()); + log.error("Public Key is not RSA or EC Public Key for cert {} of country {}", + cert.getThumbprint(), + cert.getCountry()); } - } // Add TrustedIssuer trustedIssuerService.search( - null, null, configProperties.getDid().getIncludeFederated()).stream() + null, countries, configProperties.getDid().getIncludeFederated()).stream() .filter(trustedIssuer -> trustedIssuer.getUrlType() == TrustedIssuerEntity.UrlType.DID) .forEach(trustedIssuer -> trustList.getVerificationMethod().add(trustedIssuer.getUrl())); @@ -188,7 +225,6 @@ private String generateTrustList() throws Exception { if (didContextFile == null) { log.error("Failed to load DID-Context Document for {}: No Mapping to local JSON-File.", didContext); - } try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream( @@ -208,4 +244,42 @@ private String generateTrustList() throws Exception { return jsonLdObject.toJson(); } + + private void addTrustListEntry(DidTrustListDto trustList, + TrustedCertificateTrustList cert, + DidTrustListEntryDto.PublicKeyJwk publicKeyJwk) + throws CertificateEncodingException, UnsupportedEncodingException { + Optional csca = searchForIssuer(cert); + + if (csca.isPresent()) { + publicKeyJwk.getEncodedX509Certificates() + .add(Base64.getEncoder().encodeToString(csca.get().getParsedCertificate().getEncoded())); + } + + DidTrustListEntryDto trustListEntry = new DidTrustListEntryDto(); + trustListEntry.setType("JsonWebKey2020"); + trustListEntry.setId(configProperties.getDid().getTrustListIdPrefix() + + SEPARATOR_COLON + + getCountryAsLowerCaseAlpha3(cert.getCountry()) + + SEPARATOR_FRAGMENT + + URLEncoder.encode(cert.getKid(), StandardCharsets.UTF_8)); + trustListEntry.setController(configProperties.getDid().getTrustListControllerPrefix() + + SEPARATOR_COLON + getCountryAsLowerCaseAlpha3(cert.getCountry())); + trustListEntry.setPublicKeyJwk(publicKeyJwk); + + trustList.getVerificationMethod().add(trustListEntry); + } + + @NotNull + private Optional searchForIssuer(TrustedCertificateTrustList cert) { + // Search for Issuer of DSC + return trustListService.getTrustedCertificateTrustList( + List.of(TrustedPartyEntity.CertificateType.CSCA.name()), + List.of(cert.getCountry()), + List.of(cert.getDomain()), + configProperties.getDid().getIncludeFederated()).stream() + .filter(tp -> tp.getParsedCertificate().getSubjectX500Principal() + .equals(cert.getParsedCertificate().getIssuerX500Principal())) + .findFirst(); + } } diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidUploader.java b/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidUploader.java index e79271b7..4d74bb60 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidUploader.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/did/DidUploader.java @@ -24,4 +24,6 @@ public interface DidUploader { void uploadDid(byte[] content); + void uploadDid(String subContainer, byte[] content); + } diff --git a/src/main/java/eu/europa/ec/dgc/gateway/service/did/DummyDidUploader.java b/src/main/java/eu/europa/ec/dgc/gateway/service/did/DummyDidUploader.java index 4949b519..2b3478a8 100644 --- a/src/main/java/eu/europa/ec/dgc/gateway/service/did/DummyDidUploader.java +++ b/src/main/java/eu/europa/ec/dgc/gateway/service/did/DummyDidUploader.java @@ -34,4 +34,9 @@ public void uploadDid(byte[] content) { log.info("Uploaded {} bytes", content.length); } + @Override + public void uploadDid(String subContainer, byte[] content) { + log.info("Uploaded {} bytes to subContainer {}", content.length, subContainer); + } + } diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store deleted file mode 100644 index 4530b279..00000000 Binary files a/src/main/resources/.DS_Store and /dev/null differ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 435e433f..ba197cfa 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -86,11 +86,20 @@ dgc: - DCC - SHC - CRED + - RACSEL-DDVC + trustlist: + cron: "* */5 * * * *" did: enableDidGeneration: false contextMapping: "[https://www.w3.org/ns/did/v1]": did_v1.json "[https://w3id.org/security/suites/jws-2020/v1]": jws-2020_v1.json + countryCodeMap: + virtualCountries: + XA: XXA + XB: XXB + XO: XXO + XL: XCL cloudmersive: apiKey: 0a0a0a0a-0a0a-0a0a-0a0a-0a0a0a0a0a0a url: https://api.cloudmersive.com diff --git a/src/main/resources/db/changelog.xml b/src/main/resources/db/changelog.xml index 33cdf04c..b6921e11 100644 --- a/src/main/resources/db/changelog.xml +++ b/src/main/resources/db/changelog.xml @@ -19,4 +19,7 @@ + + + diff --git a/src/main/resources/db/changelog/change-data-type-for-valuesets.xml b/src/main/resources/db/changelog/change-data-type-for-valuesets.xml new file mode 100644 index 00000000..93e52c0d --- /dev/null +++ b/src/main/resources/db/changelog/change-data-type-for-valuesets.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db/changelog/change-revocation-batch-value-type.xml b/src/main/resources/db/changelog/change-revocation-batch-value-type.xml new file mode 100644 index 00000000..44e697ae --- /dev/null +++ b/src/main/resources/db/changelog/change-revocation-batch-value-type.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/main/resources/db/changelog/change-supported-length-of-domain.xml b/src/main/resources/db/changelog/change-supported-length-of-domain.xml new file mode 100644 index 00000000..a65bbcbc --- /dev/null +++ b/src/main/resources/db/changelog/change-supported-length-of-domain.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 268f5e8c..45a45700 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -11,9 +11,7 @@ - timestamp="%d{"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", UTC}", level="%level", hostname="${HOSTNAME}", - pid="${PID:-}", thread="%thread", class="%logger{40}", message="%replace(%replace(%m){'[\r\n]+', ', - '}){'"', '\''}", trace="%X{traceId}", span="%X{spanId}", %X%n + timestamp="%d{"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", UTC}", level="%level", hostname="${HOSTNAME}", pid="${PID:-}", thread="%thread", class="%logger{40}", message="%replace(%replace(%m){'[\r\n]+', ','}){'"', '\''}", trace="%X{traceId}", span="%X{spanId}", %X%n utf8 @@ -31,10 +29,7 @@ - timestamp="%d{"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", UTC}", level="%level", hostname="${HOSTNAME}", - pid="${PID:-}", thread="%thread", class="%logger{40}", message="%replace(%replace(%m){'[\r\n]+', - ','}){'"', '\''}", exception="%replace(%ex){'[\r\n]+', ', '}", trace="%X{traceId}", span="%X{spanId}", - %X%n%nopex + timestamp="%d{"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", UTC}", level="%level", hostname="${HOSTNAME}", pid="${PID:-}", thread="%thread", class="%logger{40}", message="%replace(%replace(%m){'[\r\n]+',','}){'"', '\''}", exception="%replace(%ex){'[\r\n]+', ', '}", trace="%X{traceId}", span="%X{spanId}", %X%n%nopex utf8 diff --git a/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/TrustListIntegrationTest.java b/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/TrustListIntegrationTest.java index b92a6f6a..cc71884c 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/TrustListIntegrationTest.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/TrustListIntegrationTest.java @@ -98,7 +98,7 @@ class TrustListIntegrationTest { private static final String countryCode = "EU"; private static final String authCertSubject = "C=" + countryCode; - X509Certificate certUploadDe, certUploadEu, certCscaDe, certCscaEu, certAuthDe, certAuthEu, certDscDe, certDscEu; + X509Certificate certUploadDe, certUploadEu, certCscaDe, certCscaEu, certAuthDe, certAuthEu, certDscDe, certDscEu, certCustomEu, certTrustAnchorEu; @AfterEach public void cleanUp() { @@ -118,9 +118,14 @@ void testData() throws Exception { certAuthDe = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.AUTHENTICATION, "DE"); certAuthEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.AUTHENTICATION, "EU"); + // Add New TrustedPartyType to check that it will not be returned. + certTrustAnchorEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.TRUSTANCHOR, "EU"); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ec"); certDscDe = CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "DE", "Test"); certDscEu = CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "EU", "Test"); + certCustomEu = CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "EU", "Test"); + signerInformationRepository.save(new SignerInformationEntity( null, @@ -146,6 +151,18 @@ void testData() throws Exception { null )); + signerInformationRepository.save(new SignerInformationEntity( + null, + ZonedDateTime.now(), + "DE", + certificateUtils.getCertThumbprint(certCustomEu), + Base64.getEncoder().encodeToString(certCustomEu.getEncoded()), + "sig3", + null, + SignerInformationEntity.CertificateType.CUSTOM, + null + )); + trustedIssuerRepository.saveAll(List.of( trustedIssuerTestHelper.createTrustedIssuer("EU", "ICAO"), trustedIssuerTestHelper.createTrustedIssuer("DE", "NONE"), @@ -173,6 +190,8 @@ void testTrustListDownloadNoFilter() throws Exception { .andExpect(c -> assertTrustListItem(c, certUploadEu, "EU", CertificateTypeDto.UPLOAD, null)) .andExpect(c -> assertTrustListItem(c, certAuthDe, "DE", CertificateTypeDto.AUTHENTICATION, null)) .andExpect(c -> assertTrustListItem(c, certAuthEu, "EU", CertificateTypeDto.AUTHENTICATION, null)) + .andExpect(c -> assertTrustListDoesNotContainItem(c, certCustomEu)) + .andExpect(c -> assertTrustListDoesNotContainItem(c, certTrustAnchorEu)) .andExpect(c -> assertTrustListLength(c, 8)); } @@ -556,6 +575,22 @@ void testTrustedIssuerEmpty() throws Exception { .andExpect(jsonPath("$", hasSize(0))); } + private void assertTrustListDoesNotContainItem(MvcResult result, X509Certificate certificate) + throws UnsupportedEncodingException, JsonProcessingException { + ObjectMapper objectMapper = new ObjectMapper() + .registerModule(new JavaTimeModule()); + List trustList = + objectMapper.readValue(result.getResponse().getContentAsString(), new TypeReference<>() { + }); + + Optional trustListOptional = trustList + .stream() + .filter(tl -> tl.getKid().equals(certificateUtils.getCertKid(certificate))) + .findFirst(); + + Assertions.assertFalse(trustListOptional.isPresent()); + } + private void assertTrustListItem(MvcResult result, X509Certificate certificate, String country, CertificateTypeDto certificateTypeDto, String signature) throws CertificateEncodingException, UnsupportedEncodingException, JsonProcessingException { diff --git a/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/ValidationRuleIntegrationTest.java b/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/ValidationRuleIntegrationTest.java index a59df119..9678717e 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/ValidationRuleIntegrationTest.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/restapi/controller/ValidationRuleIntegrationTest.java @@ -603,7 +603,7 @@ void testValidationTimestamps3() throws Exception { validationRule.setValidFrom(ZonedDateTime.now().plus(3, ChronoUnit.DAYS)); validationRule.setValidTo(ZonedDateTime.now() .plus(6, ChronoUnit.DAYS) - .minus(1, ChronoUnit.SECONDS)); + .minus(2, ChronoUnit.HOURS)); String payload = new SignedStringMessageBuilder() .withSigningCertificate(certificateUtils.convertCertificate(signerCertificate), signerPrivateKey) diff --git a/src/test/java/eu/europa/ec/dgc/gateway/service/DidTrustListServiceTest.java b/src/test/java/eu/europa/ec/dgc/gateway/service/DidTrustListServiceTest.java index b2ef582c..d52fb579 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/service/DidTrustListServiceTest.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/service/DidTrustListServiceTest.java @@ -37,24 +37,30 @@ import eu.europa.ec.dgc.gateway.testdata.TrustedIssuerTestHelper; import eu.europa.ec.dgc.gateway.testdata.TrustedPartyTestHelper; import eu.europa.ec.dgc.utils.CertificateUtils; -import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.math.BigInteger; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.security.KeyPairGenerator; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; import java.time.Instant; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Base64; import java.util.LinkedHashMap; +import java.util.List; + +import foundation.identity.jsonld.JsonLDObject; import lombok.Data; import lombok.Getter; import lombok.Setter; 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.ValueSource; import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -63,7 +69,6 @@ @SpringBootTest public class DidTrustListServiceTest { - @Autowired ObjectMapper objectMapper; @@ -100,6 +105,8 @@ public class DidTrustListServiceTest { X509Certificate certUploadDe, certUploadEu, certCscaDe, certCscaEu, certAuthDe, certAuthEu, certDscDe, certDscEu, federatedCertDscEx; + String certDscDeKid; + FederationGatewayEntity federationGateway; @AfterEach @@ -107,32 +114,46 @@ public void cleanUp() { trustedPartyRepository.deleteAll(); signerInformationRepository.deleteAll(); federationGatewayRepository.deleteAll(); + trustedIssuerRepository.deleteAll(); + trustedPartyTestHelper.clear(TrustedPartyEntity.CertificateType.UPLOAD, "DE"); + trustedPartyTestHelper.clear(TrustedPartyEntity.CertificateType.UPLOAD, "EU"); + trustedPartyTestHelper.clear(TrustedPartyEntity.CertificateType.CSCA, "DE"); + trustedPartyTestHelper.clear(TrustedPartyEntity.CertificateType.CSCA, "EU"); + trustedPartyTestHelper.clear(TrustedPartyEntity.CertificateType.AUTHENTICATION, "DE"); + trustedPartyTestHelper.clear(TrustedPartyEntity.CertificateType.AUTHENTICATION, "EU"); } - @BeforeEach - void testData() throws Exception { + void testData(CertificateTestUtils.SignerType signerType) throws Exception { cleanUp(); federationGateway = - new FederationGatewayEntity(null, ZonedDateTime.now(), "gw-id", "endpoint", "kid", "pk", "impl", - FederationGatewayEntity.DownloadTarget.FEDERATION, FederationGatewayEntity.Mode.APPEND, "sig", -1L, - null, null, 0L, null, null); + new FederationGatewayEntity(null, ZonedDateTime.now(), "gw-id", "endpoint", + "kid", "pk", "impl", + FederationGatewayEntity.DownloadTarget.FEDERATION, FederationGatewayEntity.Mode.APPEND, "sig", + -1L, null, null, 0L, null, + null); federationGateway = federationGatewayRepository.save(federationGateway); - certUploadDe = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.UPLOAD, "DE"); - certUploadEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.UPLOAD, "EU"); - certCscaDe = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.CSCA, "DE"); - certCscaEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.CSCA, "EU"); - certAuthDe = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.AUTHENTICATION, "DE"); - certAuthEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.AUTHENTICATION, "EU"); + certUploadDe = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.UPLOAD, "DE", signerType); + certUploadEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.UPLOAD, "EU", signerType); + certCscaDe = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.CSCA, "DE", signerType); + certCscaEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.CSCA, "EU", signerType); + certAuthDe = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.AUTHENTICATION, "DE", signerType); + certAuthEu = trustedPartyTestHelper.getCert(TrustedPartyEntity.CertificateType.AUTHENTICATION, "EU", signerType); - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ec"); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(signerType.getSigningAlgorithm()); certDscDe = - CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "DE", "Test", certCscaDe, - trustedPartyTestHelper.getPrivateKey(TrustedPartyEntity.CertificateType.AUTHENTICATION, "DE")); + CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "DE", + "Test", certCscaDe, + trustedPartyTestHelper.getPrivateKey(TrustedPartyEntity.CertificateType.AUTHENTICATION, + "DE", signerType), signerType); + + certDscDeKid = certificateUtils.getCertKid(certDscDe); certDscEu = - CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "EU", "Test", certCscaEu, - trustedPartyTestHelper.getPrivateKey(TrustedPartyEntity.CertificateType.AUTHENTICATION, "EU")); + CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "EU", + "Test", certCscaEu, + trustedPartyTestHelper.getPrivateKey(TrustedPartyEntity.CertificateType.AUTHENTICATION, "EU", signerType), + signerType); signerInformationRepository.save(new SignerInformationEntity( null, @@ -141,7 +162,7 @@ void testData() throws Exception { certificateUtils.getCertThumbprint(certDscDe), Base64.getEncoder().encodeToString(certDscDe.getEncoded()), "sig1", - "kid1", + null, // Don't provide a KID to test that calculated KID will be used SignerInformationEntity.CertificateType.DSC, null )); @@ -158,7 +179,8 @@ void testData() throws Exception { null )); - federatedCertDscEx = CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "EX", "Test"); + federatedCertDscEx = CertificateTestUtils.generateCertificate(keyPairGenerator.generateKeyPair(), "EX", + "Test", signerType); SignerInformationEntity federatedDscEntity = new SignerInformationEntity( null, ZonedDateTime.now(), @@ -178,29 +200,40 @@ void testData() throws Exception { trustedIssuerRepository.save(trustedIssuerTestHelper.createTrustedIssuer("XY", "DCC")); } - @Test - void testTrustList() throws IOException, CertificateEncodingException { + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testTrustList(boolean isEcAlgorithm) throws Exception { + if (isEcAlgorithm) { + testData(CertificateTestUtils.SignerType.EC); + } else { + testData(CertificateTestUtils.SignerType.RSA); + } ArgumentCaptor uploadArgumentCaptor = ArgumentCaptor.forClass(byte[].class); doNothing().when(didUploaderMock).uploadDid(uploadArgumentCaptor.capture()); didTrustListService.job(); - SignedDidTrustListDto parsed = objectMapper.readValue(uploadArgumentCaptor.getValue(), SignedDidTrustListDto.class); + SignedDidTrustListDto parsed = + objectMapper.readValue(uploadArgumentCaptor.getValue(), SignedDidTrustListDto.class); Assertions.assertEquals("a", parsed.getId()); Assertions.assertEquals("b", parsed.getController()); Assertions.assertEquals(6, parsed.getVerificationMethod().size()); - assertVerificationMethod(parsed.getVerificationMethod().get(0), "kid1", certDscDe, certCscaDe); - assertVerificationMethod(parsed.getVerificationMethod().get(1), "kid2", certDscEu, certCscaEu); - assertVerificationMethod(parsed.getVerificationMethod().get(2), "kid3", federatedCertDscEx, null); + assertVerificationMethod(getVerificationMethodByKid(parsed.getVerificationMethod(), "c" + ":deu" + "#" + URLEncoder.encode(certDscDeKid, StandardCharsets.UTF_8)), + certDscDeKid, certDscDe, certCscaDe, "deu"); + assertVerificationMethod(getVerificationMethodByKid(parsed.getVerificationMethod(), "c:xeu#kid2"), + "kid2", certDscEu, certCscaEu, "xeu"); + assertVerificationMethod(getVerificationMethodByKid(parsed.getVerificationMethod(), "c:xex#kid3"), + "kid3", federatedCertDscEx, null, "xex"); Assertions.assertTrue(parsed.getVerificationMethod().contains("did:trusted:DE:issuer")); Assertions.assertTrue(parsed.getVerificationMethod().contains("did:trusted:EU:issuer")); Assertions.assertTrue(parsed.getVerificationMethod().contains("did:trusted:XY:issuer")); Assertions.assertEquals(2, parsed.getContext().size()); Assertions.assertEquals("JsonWebSignature2020", parsed.getProof().getType()); - Assertions.assertTrue(Instant.now().toEpochMilli() - parsed.getProof().getCreated().toInstant().toEpochMilli() < 10000); + Assertions.assertTrue( + Instant.now().toEpochMilli() - parsed.getProof().getCreated().toInstant().toEpochMilli() < 10000); Assertions.assertEquals("f", parsed.getProof().getDomain()); Assertions.assertEquals("g", parsed.getProof().getNonce()); Assertions.assertEquals("assertionMethod", parsed.getProof().getProofPurpose()); @@ -208,21 +241,46 @@ void testTrustList() throws IOException, CertificateEncodingException { Assertions.assertNotNull(parsed.getProof().getJws()); Assertions.assertNotEquals("", parsed.getProof().getJws()); + //JSON should start with "@context" due to https://www.w3.org/TR/json-ld11-streaming/#key-ordering-required + String json = JsonLDObject.fromJson(objectMapper.writeValueAsString(parsed)).toJson(); + String first10Characters = json.substring(0, Math.min(10, json.length())); + Assertions.assertTrue(first10Characters.contains("@context")); } - private void assertVerificationMethod(Object in, String kid, X509Certificate dsc, X509Certificate csca) - throws CertificateEncodingException { + + private Object getVerificationMethodByKid(List verificationMethods, String kid) { + return verificationMethods.stream() + .map(entry -> (LinkedHashMap) entry) + .filter(entry -> entry.get("id").equals(kid)) + .findFirst() + .orElseGet(() -> Assertions.fail("Could not find VerificationMethod with KID " + kid)); + } + + private void assertVerificationMethod(Object in, String kid, X509Certificate dsc, X509Certificate csca, String country) + throws CertificateEncodingException, UnsupportedEncodingException { LinkedHashMap jsonNode = (LinkedHashMap) in; Assertions.assertEquals("JsonWebKey2020", jsonNode.get("type")); - Assertions.assertEquals("d", jsonNode.get("controller")); - Assertions.assertEquals("c" + kid, jsonNode.get("id")); + Assertions.assertEquals("d" + ":" + country, jsonNode.get("controller")); + Assertions.assertEquals("c" + ":" + country + "#" + URLEncoder.encode(kid, StandardCharsets.UTF_8), jsonNode.get("id")); LinkedHashMap publicKeyJwk = (LinkedHashMap) jsonNode.get("publicKeyJwk"); - Assertions.assertEquals(((ECPublicKey) dsc.getPublicKey()).getW().getAffineX(), new BigInteger(Base64.getDecoder().decode(publicKeyJwk.get("x").toString()))); - Assertions.assertEquals(((ECPublicKey) dsc.getPublicKey()).getW().getAffineY(), new BigInteger(Base64.getDecoder().decode(publicKeyJwk.get("y").toString()))); - Assertions.assertEquals("EC", publicKeyJwk.get("kty").toString()); - Assertions.assertEquals("P-256", publicKeyJwk.get("crv").toString()); + if (dsc.getPublicKey().getAlgorithm().equals(CertificateTestUtils.SignerType.EC.getSigningAlgorithm())) { + Assertions.assertEquals(((ECPublicKey) dsc.getPublicKey()).getW().getAffineX(), + new BigInteger(Base64.getDecoder().decode(publicKeyJwk.get("x").toString()))); + Assertions.assertEquals(((ECPublicKey) dsc.getPublicKey()).getW().getAffineY(), + new BigInteger(Base64.getDecoder().decode(publicKeyJwk.get("y").toString()))); + Assertions.assertEquals(CertificateTestUtils.SignerType.EC.getSigningAlgorithm(), + publicKeyJwk.get("kty").toString()); + Assertions.assertEquals("P-256", publicKeyJwk.get("crv").toString()); + } else { + Assertions.assertEquals(((RSAPublicKey) dsc.getPublicKey()).getPublicExponent(), + new BigInteger(Base64.getDecoder().decode(publicKeyJwk.get("e").toString()))); + Assertions.assertEquals(((RSAPublicKey) dsc.getPublicKey()).getModulus(), + new BigInteger(Base64.getDecoder().decode(publicKeyJwk.get("n").toString()))); + Assertions.assertEquals(CertificateTestUtils.SignerType.RSA.getSigningAlgorithm(), + publicKeyJwk.get("kty").toString()); + } ArrayList x5c = ((ArrayList) publicKeyJwk.get("x5c")); Assertions.assertEquals(Base64.getEncoder().encodeToString(dsc.getEncoded()), x5c.get(0)); if (csca != null) { diff --git a/src/test/java/eu/europa/ec/dgc/gateway/testdata/CertificateTestUtils.java b/src/test/java/eu/europa/ec/dgc/gateway/testdata/CertificateTestUtils.java index 903b9bf3..e1e20373 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/testdata/CertificateTestUtils.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/testdata/CertificateTestUtils.java @@ -31,6 +31,10 @@ import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.List; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameBuilder; import org.bouncycastle.asn1.x509.BasicConstraints; @@ -73,7 +77,15 @@ public static X509Certificate generateCertificate(KeyPair keyPair, String countr Date validFrom = Date.from(Instant.now().minus(1, ChronoUnit.DAYS)); Date validTo = Date.from(Instant.now().plus(365, ChronoUnit.DAYS)); - return generateCertificate(keyPair, country, commonName, validFrom, validTo); + return generateCertificate(keyPair, country, commonName, validFrom, validTo, SignerType.EC); + } + + public static X509Certificate generateCertificate(KeyPair keyPair, String country, String commonName, + SignerType signerType) throws Exception { + Date validFrom = Date.from(Instant.now().minus(1, ChronoUnit.DAYS)); + Date validTo = Date.from(Instant.now().plus(365, ChronoUnit.DAYS)); + + return generateCertificate(keyPair, country, commonName, validFrom, validTo, signerType); } public static X509Certificate generateCertificate(KeyPair keyPair, String country, String commonName, @@ -81,11 +93,21 @@ public static X509Certificate generateCertificate(KeyPair keyPair, String countr Date validFrom = Date.from(Instant.now().minus(1, ChronoUnit.DAYS)); Date validTo = Date.from(Instant.now().plus(365, ChronoUnit.DAYS)); - return generateCertificate(keyPair, country, commonName, validFrom, validTo, ca, caKey); + return generateCertificate(keyPair, country, commonName, validFrom, validTo, ca, caKey, SignerType.EC); + } + + public static X509Certificate generateCertificate(KeyPair keyPair, String country, String commonName, + X509Certificate ca, PrivateKey caKey, + SignerType signerType) throws Exception { + Date validFrom = Date.from(Instant.now().minus(1, ChronoUnit.DAYS)); + Date validTo = Date.from(Instant.now().plus(365, ChronoUnit.DAYS)); + + return generateCertificate(keyPair, country, commonName, validFrom, validTo, ca, caKey, signerType); } public static X509Certificate generateCertificate(KeyPair keyPair, String country, String commonName, - Date validFrom, Date validTo) throws Exception { + Date validFrom, Date validTo, + SignerType signerType) throws Exception { X500Name subject = new X500NameBuilder() .addRDN(X509ObjectIdentifiers.countryName, country) .addRDN(X509ObjectIdentifiers.commonName, commonName) @@ -93,7 +115,7 @@ public static X509Certificate generateCertificate(KeyPair keyPair, String countr BigInteger certSerial = new BigInteger(Long.toString(System.currentTimeMillis())); - ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(keyPair.getPrivate()); + ContentSigner contentSigner = new JcaContentSignerBuilder(signerType.signingMethod).build(keyPair.getPrivate()); JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(subject, certSerial, validFrom, validTo, subject, keyPair.getPublic()); @@ -106,7 +128,7 @@ public static X509Certificate generateCertificate(KeyPair keyPair, String countr public static X509Certificate generateCertificate(KeyPair keyPair, String country, String commonName, Date validFrom, Date validTo, X509Certificate ca, - PrivateKey caKey) throws Exception { + PrivateKey caKey, SignerType signerType) throws Exception { X500Name subject = new X500NameBuilder() .addRDN(X509ObjectIdentifiers.countryName, country) .addRDN(X509ObjectIdentifiers.commonName, commonName) @@ -116,7 +138,7 @@ public static X509Certificate generateCertificate(KeyPair keyPair, String countr BigInteger certSerial = new BigInteger(Long.toString(System.currentTimeMillis())); - ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(caKey); + ContentSigner contentSigner = new JcaContentSignerBuilder(signerType.signingMethod).build(caKey); JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuer, certSerial, validFrom, validTo, subject, keyPair.getPublic()); @@ -144,4 +166,14 @@ public static void assertEquals(ValidationRule v1, ValidationRule v2) { Assertions.assertEquals(v1.getLogic(), v2.getLogic()); } + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + @Getter + public static class SignerType { + + private final String signingMethod; + private final String signingAlgorithm; + + public static SignerType RSA = new SignerType("SHA256withRSA", "RSA"); + public static SignerType EC = new SignerType("SHA256withECDSA", "EC"); + } } diff --git a/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedIssuerTestHelper.java b/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedIssuerTestHelper.java index 5a79bcdc..e5d69ff0 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedIssuerTestHelper.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedIssuerTestHelper.java @@ -51,10 +51,9 @@ public TrustedIssuerEntity createTrustedIssuer(final String country, final Strin } private String getHashData(TrustedIssuerEntity entity) { - return entity.getUuid() + ";" - + entity.getCountry() + ";" + return entity.getCountry() + ";" + entity.getName() + ";" + entity.getUrl() + ";" - + entity.getUrlType().name() + ";"; + + entity.getUrlType().name(); } } diff --git a/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedPartyTestHelper.java b/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedPartyTestHelper.java index b4571f9a..73f8037b 100644 --- a/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedPartyTestHelper.java +++ b/src/test/java/eu/europa/ec/dgc/gateway/testdata/TrustedPartyTestHelper.java @@ -45,19 +45,22 @@ public class TrustedPartyTestHelper { private final Map> hashMap = Map.of( TrustedPartyEntity.CertificateType.AUTHENTICATION, new HashMap<>(), TrustedPartyEntity.CertificateType.CSCA, new HashMap<>(), - TrustedPartyEntity.CertificateType.UPLOAD, new HashMap<>() + TrustedPartyEntity.CertificateType.UPLOAD, new HashMap<>(), + TrustedPartyEntity.CertificateType.TRUSTANCHOR, new HashMap<>() ); private final Map> certificateMap = Map.of( TrustedPartyEntity.CertificateType.AUTHENTICATION, new HashMap<>(), TrustedPartyEntity.CertificateType.CSCA, new HashMap<>(), - TrustedPartyEntity.CertificateType.UPLOAD, new HashMap<>() + TrustedPartyEntity.CertificateType.UPLOAD, new HashMap<>(), + TrustedPartyEntity.CertificateType.TRUSTANCHOR, new HashMap<>() ); private final Map> privateKeyMap = Map.of( TrustedPartyEntity.CertificateType.AUTHENTICATION, new HashMap<>(), TrustedPartyEntity.CertificateType.CSCA, new HashMap<>(), - TrustedPartyEntity.CertificateType.UPLOAD, new HashMap<>() + TrustedPartyEntity.CertificateType.UPLOAD, new HashMap<>(), + TrustedPartyEntity.CertificateType.TRUSTANCHOR, new HashMap<>() ); private final TrustedPartyRepository trustedPartyRepository; @@ -72,17 +75,29 @@ public X509Certificate getTestCert(String testCertId, TrustedPartyEntity.Certifi } public String getHash(TrustedPartyEntity.CertificateType type, String countryCode) throws Exception { - prepareTestCert(type, countryCode); + prepareTestCert(type, countryCode, CertificateTestUtils.SignerType.EC); return hashMap.get(type).get(countryCode); } public X509Certificate getCert(TrustedPartyEntity.CertificateType type, String countryCode) throws Exception { - prepareTestCert(type, countryCode); + prepareTestCert(type, countryCode, CertificateTestUtils.SignerType.EC); + return certificateMap.get(type).get(countryCode); + } + + public X509Certificate getCert(TrustedPartyEntity.CertificateType type, String countryCode, + CertificateTestUtils.SignerType signerType) throws Exception { + prepareTestCert(type, countryCode, signerType); return certificateMap.get(type).get(countryCode); } public PrivateKey getPrivateKey(TrustedPartyEntity.CertificateType type, String countryCode) throws Exception { - prepareTestCert(type, countryCode); + prepareTestCert(type, countryCode, CertificateTestUtils.SignerType.EC); + return privateKeyMap.get(type).get(countryCode); + } + + public PrivateKey getPrivateKey(TrustedPartyEntity.CertificateType type, String countryCode, + CertificateTestUtils.SignerType signerType) throws Exception { + prepareTestCert(type, countryCode, signerType); return privateKeyMap.get(type).get(countryCode); } @@ -103,10 +118,11 @@ public void clear(TrustedPartyEntity.CertificateType type, String countryCode) { privateKeyMap.get(type).remove(countryCode); } - private void prepareTestCert(TrustedPartyEntity.CertificateType type, String countryCode) throws Exception { + private void prepareTestCert(TrustedPartyEntity.CertificateType type, String countryCode, + CertificateTestUtils.SignerType signerType) throws Exception { // Check if a test certificate already exists if (!hashMap.get(type).containsKey(countryCode)) { - createAndInsertCert(type, countryCode); + createAndInsertCert(type, countryCode, signerType); } // Check if generated certificate is (still) present in DB @@ -117,11 +133,12 @@ private void prepareTestCert(TrustedPartyEntity.CertificateType type, String cou } } - private void createAndInsertCert(TrustedPartyEntity.CertificateType type, String countryCode) throws Exception { - KeyPair keyPair = KeyPairGenerator.getInstance("ec").generateKeyPair(); + private void createAndInsertCert(TrustedPartyEntity.CertificateType type, String countryCode, + CertificateTestUtils.SignerType signerType) throws Exception { + KeyPair keyPair = KeyPairGenerator.getInstance(signerType.getSigningAlgorithm()).generateKeyPair(); X509Certificate authCertificate = CertificateTestUtils.generateCertificate(keyPair, countryCode, - "DGC Test " + type.name() + " Cert"); + "DGC Test " + type.name() + " Cert", signerType); certificateMap.get(type).put(countryCode, authCertificate); hashMap.get(type).put(countryCode, certificateUtils.getCertThumbprint(authCertificate)); diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 70f3dd91..d0efa1ae 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -58,3 +58,11 @@ dgc: apiKey: 0a0a0a0a-0a0a-0a0a-0a0a-0a0a0a0a0a0a enabled: true url: https://api.cloudmersive.com + countryCodeMap: + virtualCountries: + XA: XXA + XB: XXB + XO: XXO + XL: XCL + EU: XEU + EX: XEX \ No newline at end of file