diff --git a/src/main/kotlin/fr/gouv/stopc/submissioncode/service/SubmissionCodeService.kt b/src/main/kotlin/fr/gouv/stopc/submissioncode/service/SubmissionCodeService.kt index 3fe030896d89bfd9ac5cf54269773eae39f8b21a..5ddbaee2f349b33cb3c407b546119176a9a3efac 100644 --- a/src/main/kotlin/fr/gouv/stopc/submissioncode/service/SubmissionCodeService.kt +++ b/src/main/kotlin/fr/gouv/stopc/submissioncode/service/SubmissionCodeService.kt @@ -1,5 +1,6 @@ package fr.gouv.stopc.submissioncode.service +import com.nimbusds.jose.JOSEException import com.nimbusds.jose.JWSVerifier import com.nimbusds.jwt.SignedJWT import fr.gouv.stopc.submissioncode.configuration.SubmissionProperties @@ -187,9 +188,15 @@ class SubmissionCodeService( return false } - if (!signedJwt.verify(jwtSignatureVerifiers[kid])) { + try { + if (!signedJwt.verify(jwtSignatureVerifiers[kid])) { + metricsService.countCodeUsed(JWT, false) + log.info("JWT signature is invalid: $jwt") + return false + } + } catch (e: JOSEException) { metricsService.countCodeUsed(JWT, false) - log.info("JWT signature is invalid: $jwt") + log.info("JWT signature can't be verified: ${e.message}, $jwt") return false } diff --git a/src/test/kotlin/fr/gouv/stopc/submissioncode/controller/VerifyControllerTest.kt b/src/test/kotlin/fr/gouv/stopc/submissioncode/controller/VerifyControllerTest.kt index cd0c77db10a58fa502172381ff6cca0ce0fef554..129f84779de8b5cbff1c65fbb221ab0c77e21ec6 100644 --- a/src/test/kotlin/fr/gouv/stopc/submissioncode/controller/VerifyControllerTest.kt +++ b/src/test/kotlin/fr/gouv/stopc/submissioncode/controller/VerifyControllerTest.kt @@ -28,6 +28,7 @@ import org.springframework.http.HttpStatus.OK import java.time.Instant import java.time.temporal.ChronoUnit.DAYS import java.time.temporal.ChronoUnit.MINUTES +import java.util.Base64 import java.util.UUID import java.util.stream.Stream @@ -389,5 +390,31 @@ class VerifyControllerTest { assertThat(output.all) .containsPattern("JWT could not be parsed: Invalid JWS header: Invalid JSON: Unexpected token [^ ]+ at position 5., aaaaaaa.aaaaaaa.aaaaaaa") } + + @Test + fun reject_a_JWT_with_invalid_alg_header_field(output: CapturedOutput) { + + val invalidHeader = """ + { + "alg": "invalid alg", + "typ": "JWT", + "kid": "TousAntiCovidKID" + } + """.trimIndent() + .toByteArray() + .let { Base64.getEncoder().encodeToString(it) } + + val jwtWithInvalidHeader = givenJwt().replaceBefore(".", invalidHeader) + + When() + .get("/api/v1/verify?code={jwt}", jwtWithInvalidHeader) + + .then() + .statusCode(OK.value()) + .body("valid", equalTo(false)) + + assertThat(output.all) + .contains("JWT signature can't be verified: Unsupported JWS algorithm invalid alg, must be ES256, $jwtWithInvalidHeader") + } } }