package com.auth0.jwt.algorithms; import com.auth0.jwt.JWT; import com.auth0.jwt.exceptions.SignatureGenerationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.ECDSAKeyProvider; import org.apache.commons.codec.binary.Base64; import org.hamcrest.Matchers; import org.hamcrest.collection.IsIn; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.security.*; import java.security.interfaces.ECKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.util.Arrays; import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @SuppressWarnings("deprecation") public class ECDSAAlgorithmTest { private static final String PRIVATE_KEY_FILE_256 = "src/test/resources/ec256-key-private.pem"; private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; private static final String INVALID_PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public-invalid.pem"; private static final String PRIVATE_KEY_FILE_384 = "src/test/resources/ec384-key-private.pem"; private static final String PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public.pem"; private static final String INVALID_PUBLIC_KEY_FILE_384 = "src/test/resources/ec384-key-public-invalid.pem"; private static final String PRIVATE_KEY_FILE_512 = "src/test/resources/ec512-key-private.pem"; private static final String PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public.pem"; private static final String INVALID_PUBLIC_KEY_FILE_512 = "src/test/resources/ec512-key-public-invalid.pem"; @Rule public ExpectedException exception = ExpectedException.none(); //JOSE Signatures obtained using Node 'jwa' lib: https://github.com/brianloveswords/node-jwa //DER Signatures obtained from source JOSE signature using 'ecdsa-sig-formatter' lib: https://github.com/Brightspace/node-ecdsa-sig-formatter //These tests use the default preferred SecurityProvider to handle ECDSA algorithms // Verify @Test public void shouldPassECDSA256VerificationWithJOSESignature() throws Exception { String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); Algorithm algorithm = Algorithm.ECDSA256(key); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnECDSA256VerificationWithDERSignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); Algorithm algorithm = Algorithm.ECDSA256(key); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA256VerificationWithJOSESignatureWithBothKeys() throws Exception { String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnECDSA256VerificationWithDERSignatureWithBothKeys() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA256VerificationWithProvidedPublicKey() throws Exception { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); String jwt = "eyJhbGciOiJFUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.D_oU4CB0ZEsxHOjcWnmS3ZJvlTzm6WcGFx-HASxnvcB2Xu2WjI-axqXH9xKq45aPBDs330JpRhJmqBSc2K8MXQ"; Algorithm algorithm = Algorithm.ECDSA256(provider); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Public Key is null."))); ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPublicKeyById("my-key-id")).thenReturn(null); String jwt = "eyJhbGciOiJFUzI1NiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.D_oU4CB0ZEsxHOjcWnmS3ZJvlTzm6WcGFx-HASxnvcB2Xu2WjI-axqXH9xKq45aPBDs330JpRhJmqBSc2K8MXQ"; Algorithm algorithm = Algorithm.ECDSA256(provider); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA256VerificationWithInvalidPublicKey() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.W9qfN1b80B9hnMo49WL8THrOsf1vEjOhapeFemPMGySzxTcgfyudS5esgeBTO908X5SLdAr5jMwPUPBs9b6nNg"; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA256VerificationWhenUsingPrivateKey() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Public Key is null."))); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.W9qfN1b80B9hnMo49WL8THrOsf1vEjOhapeFemPMGySzxTcgfyudS5esgeBTO908X5SLdAr5jMwPUPBs9b6nNg"; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA256VerificationOnInvalidJOSESignatureLength() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); byte[] bytes = new byte[63]; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA256VerificationOnInvalidJOSESignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); byte[] bytes = new byte[64]; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA256VerificationOnInvalidDERSignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); byte[] bytes = new byte[64]; bytes[0] = 0x30; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA384VerificationWithJOSESignature() throws Exception { String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); Algorithm algorithm = Algorithm.ECDSA384(key); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnECDSA384VerificationWithDERSignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UtccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); Algorithm algorithm = Algorithm.ECDSA384(key); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA384VerificationWithJOSESignatureWithBothKeys() throws Exception { String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.50UU5VKNdF1wfykY8jQBKpvuHZoe6IZBJm5NvoB8bR-hnRg6ti-CHbmvoRtlLfnHfwITa_8cJMy6TenMC2g63GQHytc8rYoXqbwtS4R0Ko_AXbLFUmfxnGnMC6v4MS_z"; Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnECDSA384VerificationWithDERSignatureWithBothKeys() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA384VerificationWithProvidedPublicKey() throws Exception { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); String jwt = "eyJhbGciOiJFUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.9kjGuFTPx3ylfpqL0eY9H7TGmPepjQOBKI8UPoEvby6N7dDLF5HxLohosNxxFymNT7LzpeSgOPAB0wJEwG2Nl2ukgdUOpZOf492wog_i5ZcZmAykd3g1QH7onrzd69GU"; Algorithm algorithm = Algorithm.ECDSA384(provider); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Public Key is null."))); ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPublicKeyById("my-key-id")).thenReturn(null); String jwt = "eyJhbGciOiJFUzM4NCIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.9kjGuFTPx3ylfpqL0eY9H7TGmPepjQOBKI8UPoEvby6N7dDLF5HxLohosNxxFymNT7LzpeSgOPAB0wJEwG2Nl2ukgdUOpZOf492wog_i5ZcZmAykd3g1QH7onrzd69GU"; Algorithm algorithm = Algorithm.ECDSA384(provider); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA384VerificationWithInvalidPublicKey() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9._k5h1KyO-NE0R2_HAw0-XEc0bGT5atv29SxHhOGC9JDqUHeUdptfCK_ljQ01nLVt2OQWT2SwGs-TuyHDFmhPmPGFZ9wboxvq_ieopmYqhQilNAu-WF-frioiRz9733fU"; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA384VerificationWhenUsingPrivateKey() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Public Key is null."))); String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9._k5h1KyO-NE0R2_HAw0-XEc0bGT5atv29SxHhOGC9JDqUHeUdptfCK_ljQ01nLVt2OQWT2SwGs-TuyHDFmhPmPGFZ9wboxvq_ieopmYqhQilNAu-WF-frioiRz9733fU"; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA384VerificationOnInvalidJOSESignatureLength() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); byte[] bytes = new byte[95]; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA384VerificationOnInvalidJOSESignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); byte[] bytes = new byte[96]; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA384VerificationOnInvalidDERSignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); byte[] bytes = new byte[96]; new SecureRandom().nextBytes(bytes); bytes[0] = 0x30; String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA512VerificationWithJOSESignature() throws Exception { String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); Algorithm algorithm = Algorithm.ECDSA512(key); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnECDSA512VerificationWithDERSignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); Algorithm algorithm = Algorithm.ECDSA512(key); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA512VerificationWithJOSESignatureWithBothKeys() throws Exception { String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AeCJPDIsSHhwRSGZCY6rspi8zekOw0K9qYMNridP1Fu9uhrA1QrG-EUxXlE06yvmh2R7Rz0aE7kxBwrnq8L8aOBCAYAsqhzPeUvyp8fXjjgs0Eto5I0mndE2QHlgcMSFASyjHbU8wD2Rq7ZNzGQ5b2MZfpv030WGUajT-aZYWFUJHVg2"; Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowECDSA512VerificationWithDERSignatureWithBothKeys() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldPassECDSA512VerificationWithProvidedPublicKey() throws Exception { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); when(provider.getPublicKeyById("my-key-id")).thenReturn((ECPublicKey) publicKey); String jwt = "eyJhbGciOiJFUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.AGxEwbsYa2bQ7Y7DAcTQnVD8PmLSlhJ20jg2OfdyPnqdXI8SgBaG6lGciq3_pofFhs1HEoFoJ33Jcluha24oMHIvAfwu8qbv_Wq3L2eI9Q0L0p6ul8Pd_BS8adRa2PgLc36xXGcRc7ID5YH-CYaQfsTp5YIaF0Po3h0QyCoQ6ZiYQkqm"; Algorithm algorithm = Algorithm.ECDSA512(provider); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Public Key is null."))); ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPublicKeyById("my-key-id")).thenReturn(null); String jwt = "eyJhbGciOiJFUzUxMiIsImtpZCI6Im15LWtleS1pZCJ9.eyJpc3MiOiJhdXRoMCJ9.AGxEwbsYa2bQ7Y7DAcTQnVD8PmLSlhJ20jg2OfdyPnqdXI8SgBaG6lGciq3_pofFhs1HEoFoJ33Jcluha24oMHIvAfwu8qbv_Wq3L2eI9Q0L0p6ul8Pd_BS8adRa2PgLc36xXGcRc7ID5YH-CYaQfsTp5YIaF0Po3h0QyCoQ6ZiYQkqm"; Algorithm algorithm = Algorithm.ECDSA512(provider); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA512VerificationWithInvalidPublicKey() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AZgdopFFsN0amCSs2kOucXdpylD31DEm5ChK1PG0_gq5Mf47MrvVph8zHSVuvcrXzcE1U3VxeCg89mYW1H33Y-8iAF0QFkdfTUQIWKNObH543WNMYYssv3OtOj0znPv8atDbaF8DMYAtcT1qdmaSJRhx-egRE9HGZkinPh9CfLLLt58X"; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA512VerificationWhenUsingPrivateKey() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Public Key is null."))); String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.AZgdopFFsN0amCSs2kOucXdpylD31DEm5ChK1PG0_gq5Mf47MrvVph8zHSVuvcrXzcE1U3VxeCg89mYW1H33Y-8iAF0QFkdfTUQIWKNObH543WNMYYssv3OtOj0znPv8atDbaF8DMYAtcT1qdmaSJRhx-egRE9HGZkinPh9CfLLLt58X"; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA512VerificationOnInvalidJOSESignatureLength() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); byte[] bytes = new byte[131]; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA512VerificationOnInvalidJOSESignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); byte[] bytes = new byte[132]; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailECDSA512VerificationOnInvalidDERSignature() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); byte[] bytes = new byte[132]; new SecureRandom().nextBytes(bytes); bytes[0] = 0x30; String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailJOSEToDERConversionOnInvalidJOSESignatureLength() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); byte[] bytes = new byte[256]; new SecureRandom().nextBytes(bytes); String signature = Base64.encodeBase64URLSafeString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm("ES256", "SHA256withECDSA", 128, provider); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnVerifyWhenSignatureAlgorithmDoesNotExists() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); exception.expectCause(isA(NoSuchAlgorithmException.class)); CryptoHelper crypto = mock(CryptoHelper.class); when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) .thenThrow(NoSuchAlgorithmException.class); ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnVerifyWhenThePublicKeyIsInvalid() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); exception.expectCause(isA(InvalidKeyException.class)); CryptoHelper crypto = mock(CryptoHelper.class); when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) .thenThrow(InvalidKeyException.class); ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; algorithm.verify(JWT.decode(jwt)); } @Test public void shouldThrowOnVerifyWhenTheSignatureIsNotPrepared() throws Exception { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: some-alg"); exception.expectCause(isA(SignatureException.class)); CryptoHelper crypto = mock(CryptoHelper.class); when(crypto.verifySignatureFor(anyString(), any(PublicKey.class), any(String.class), any(String.class), any(byte[].class))) .thenThrow(SignatureException.class); ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.4iVk3-Y0v4RT4_9IaQlp-8dZ_4fsTzIylgrPTDLrEvTHBTyVS3tgPbr2_IZfLETtiKRqCg0aQ5sh9eIsTTwB1g"; algorithm.verify(JWT.decode(jwt)); } //Sign private static final String ES256Header = "eyJhbGciOiJFUzI1NiJ9"; private static final String ES384Header = "eyJhbGciOiJFUzM4NCJ9"; private static final String ES512Header = "eyJhbGciOiJFUzUxMiJ9"; private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; private static final byte[] ES256HeaderBytes = ES256Header.getBytes(StandardCharsets.UTF_8); private static final byte[] ES384HeaderBytes = ES384Header.getBytes(StandardCharsets.UTF_8); private static final byte[] ES512HeaderBytes = ES512Header.getBytes(StandardCharsets.UTF_8); private static final byte[] auth0IssPayloadBytes = auth0IssPayload.getBytes(StandardCharsets.UTF_8); @Test public void shouldDoECDSA256Signing() throws Exception { Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); Algorithm algorithmVerify = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC")); String jwt = asJWT(algorithm, ES256Header, auth0IssPayload); assertSignaturePresent(jwt); algorithmVerify.verify(JWT.decode(jwt)); } @Test public void shouldDoECDSA256SigningWithBothKeys() throws Exception { Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] signatureBytes = algorithm.sign(ES256HeaderBytes, auth0IssPayloadBytes); String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes); String jwt = String.format("%s.%s.%s", ES256Header, auth0IssPayload, jwtSignature); assertSignaturePresent(jwt); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldDoECDSA256SigningWithProvidedPrivateKey() throws Exception { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC"); PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); Algorithm algorithm = Algorithm.ECDSA256(provider); String jwt = asJWT(algorithm, ES256Header, auth0IssPayload); assertSignaturePresent(jwt); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Private Key is null."))); ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKey()).thenReturn(null); Algorithm algorithm = Algorithm.ECDSA256(provider); algorithm.sign(new byte[0], new byte[0]); } @Test public void shouldFailOnECDSA256SigningWhenUsingPublicKey() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Private Key is null."))); Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC")); algorithm.sign(new byte[0], new byte[0]); } @Test public void shouldDoECDSA384Signing() throws Exception { Algorithm algorithmSign = Algorithm.ECDSA384((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); Algorithm algorithmVerify = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC")); String jwt = asJWT(algorithmSign, ES384Header, auth0IssPayload); assertSignaturePresent(jwt); algorithmVerify.verify(JWT.decode(jwt)); } @Test public void shouldDoECDSA384SigningWithBothKeys() throws Exception { Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); String jwt = asJWT(algorithm, ES384Header, auth0IssPayload); assertSignaturePresent(jwt); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldDoECDSA384SigningWithProvidedPrivateKey() throws Exception { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC"); PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); Algorithm algorithm = Algorithm.ECDSA384(provider); String jwt = asJWT(algorithm, ES384Header, auth0IssPayload); assertSignaturePresent(jwt); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Private Key is null."))); ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKey()).thenReturn(null); Algorithm algorithm = Algorithm.ECDSA384(provider); algorithm.sign(new byte[0], new byte[0]); } @Test public void shouldFailOnECDSA384SigningWhenUsingPublicKey() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Private Key is null."))); Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC")); algorithm.sign(new byte[0], new byte[0]); } @Test public void shouldDoECDSA512Signing() throws Exception { Algorithm algorithmSign = Algorithm.ECDSA512((ECKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); Algorithm algorithmVerify = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC")); String jwt = asJWT(algorithmSign, ES512Header, auth0IssPayload); assertSignaturePresent(jwt); algorithmVerify.verify(JWT.decode(jwt)); } @Test public void shouldDoECDSA512SigningWithBothKeys() throws Exception { Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); String jwt = asJWT(algorithm, ES512Header, auth0IssPayload); assertSignaturePresent(jwt); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldDoECDSA512SigningWithProvidedPrivateKey() throws Exception { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); PrivateKey privateKey = readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC"); PublicKey publicKey = readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); when(provider.getPrivateKey()).thenReturn((ECPrivateKey) privateKey); when(provider.getPublicKeyById(null)).thenReturn((ECPublicKey) publicKey); Algorithm algorithm = Algorithm.ECDSA512(provider); String jwt = asJWT(algorithm, ES512Header, auth0IssPayload); assertSignaturePresent(jwt); algorithm.verify(JWT.decode(jwt)); } @Test public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Private Key is null."))); ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKey()).thenReturn(null); Algorithm algorithm = Algorithm.ECDSA512(provider); algorithm.sign(new byte[0], new byte[0]); } @Test public void shouldFailOnECDSA512SigningWhenUsingPublicKey() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Private Key is null."))); Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC")); algorithm.sign(new byte[0], new byte[0]); } @Test public void shouldThrowOnSignWhenSignatureAlgorithmDoesNotExists() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); exception.expectCause(isA(NoSuchAlgorithmException.class)); CryptoHelper crypto = mock(CryptoHelper.class); when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) .thenThrow(NoSuchAlgorithmException.class); ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); algorithm.sign(ES256HeaderBytes, new byte[0]); } @Test public void shouldThrowOnSignWhenThePrivateKeyIsInvalid() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); exception.expectCause(isA(InvalidKeyException.class)); CryptoHelper crypto = mock(CryptoHelper.class); when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) .thenThrow(InvalidKeyException.class); ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); algorithm.sign(ES256HeaderBytes, new byte[0]); } @Test public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: some-algorithm"); exception.expectCause(isA(SignatureException.class)); CryptoHelper crypto = mock(CryptoHelper.class); when(crypto.createSignatureFor(anyString(), any(PrivateKey.class), any(byte[].class), any(byte[].class))) .thenThrow(SignatureException.class); ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm(crypto, "some-alg", "some-algorithm", 32, provider); algorithm.sign(ES256HeaderBytes, new byte[0]); } @Test public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Exception { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); assertThat(algorithm.getSigningKeyId(), is(nullValue())); } @Test public void shouldReturnSigningKeyIdFromProvider() throws Exception { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKeyId()).thenReturn("keyId"); Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); assertThat(algorithm.getSigningKeyId(), is("keyId")); } @Test public void shouldThrowOnDERSignatureConversionIfDoesNotStartWithCorrectSequenceByte() throws Exception { exception.expect(SignatureException.class); exception.expectMessage("Invalid DER signature format."); ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); String content256 = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9"; byte[] signature = algorithm256.sign(content256.getBytes(), new byte[0]); signature[0] = (byte) 0x02; algorithm256.DERToJOSE(signature); } @Test public void shouldThrowOnDERSignatureConversionIfDoesNotHaveExpectedLength() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] derSignature = createDERSignature(32, false, false); int received = (int) derSignature[1]; received--; derSignature[1] = (byte) received; exception.expect(SignatureException.class); exception.expectMessage("Invalid DER signature format."); algorithm256.DERToJOSE(derSignature); } @Test public void shouldThrowOnDERSignatureConversionIfRNumberDoesNotHaveExpectedLength() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] derSignature = createDERSignature(32, false, false); derSignature[3] = (byte) 34; exception.expect(SignatureException.class); exception.expectMessage("Invalid DER signature format."); algorithm256.DERToJOSE(derSignature); } @Test public void shouldThrowOnDERSignatureConversionIfSNumberDoesNotHaveExpectedLength() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] derSignature = createDERSignature(32, false, false); derSignature[4 + 32 + 1] = (byte) 34; exception.expect(SignatureException.class); exception.expectMessage("Invalid DER signature format."); algorithm256.DERToJOSE(derSignature); } @Test public void shouldThrowOnJOSESignatureConversionIfDoesNotHaveExpectedLength() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] joseSignature = new byte[32 * 2 - 1]; exception.expect(SignatureException.class); exception.expectMessage("Invalid JOSE signature format."); algorithm256.JOSEToDER(joseSignature); } @Test public void shouldSignAndVerifyWithECDSA256() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); String header256 = "eyJhbGciOiJFUzI1NiJ9"; String body = "eyJpc3MiOiJhdXRoMCJ9"; for (int i = 0; i < 10; i++) { String jwt = asJWT(algorithm256, header256, body); algorithm256.verify(JWT.decode(jwt)); } } @Test public void shouldSignAndVerifyWithECDSA384() throws Exception { ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); String header384 = "eyJhbGciOiJFUzM4NCJ9"; String body = "eyJpc3MiOiJhdXRoMCJ9"; for (int i = 0; i < 10; i++) { String jwt = asJWT(algorithm384, header384, body); algorithm384.verify(JWT.decode(jwt)); } } @Test public void shouldSignAndVerifyWithECDSA512() throws Exception { ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); String header512 = "eyJhbGciOiJFUzUxMiJ9"; String body = "eyJpc3MiOiJhdXRoMCJ9"; for (int i = 0; i < 10; i++) { String jwt = asJWT(algorithm512, header512, body); algorithm512.verify(JWT.decode(jwt)); } } @Test public void shouldDecodeECDSA256JOSE() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); //Without padding byte[] joseSignature = createJOSESignature(32, false, false); byte[] derSignature = algorithm256.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 32, false, false); //With R padding joseSignature = createJOSESignature(32, true, false); derSignature = algorithm256.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 32, true, false); //With S padding joseSignature = createJOSESignature(32, false, true); derSignature = algorithm256.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 32, false, true); //With both paddings joseSignature = createJOSESignature(32, true, true); derSignature = algorithm256.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 32, true, true); } @Test public void shouldDecodeECDSA256DER() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); //Without padding byte[] derSignature = createDERSignature(32, false, false); byte[] joseSignature = algorithm256.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 32, false, false); //With R padding derSignature = createDERSignature(32, true, false); joseSignature = algorithm256.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 32, true, false); //With S padding derSignature = createDERSignature(32, false, true); joseSignature = algorithm256.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 32, false, true); //With both paddings derSignature = createDERSignature(32, true, true); joseSignature = algorithm256.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 32, true, true); } @Test public void shouldDecodeECDSA384JOSE() throws Exception { ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); //Without padding byte[] joseSignature = createJOSESignature(48, false, false); byte[] derSignature = algorithm384.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 48, false, false); //With R padding joseSignature = createJOSESignature(48, true, false); derSignature = algorithm384.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 48, true, false); //With S padding joseSignature = createJOSESignature(48, false, true); derSignature = algorithm384.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 48, false, true); //With both paddings joseSignature = createJOSESignature(48, true, true); derSignature = algorithm384.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 48, true, true); } @Test public void shouldDecodeECDSA384DER() throws Exception { ECDSAAlgorithm algorithm384 = (ECDSAAlgorithm) Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); //Without padding byte[] derSignature = createDERSignature(48, false, false); byte[] joseSignature = algorithm384.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 48, false, false); //With R padding derSignature = createDERSignature(48, true, false); joseSignature = algorithm384.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 48, true, false); //With S padding derSignature = createDERSignature(48, false, true); joseSignature = algorithm384.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 48, false, true); //With both paddings derSignature = createDERSignature(48, true, true); joseSignature = algorithm384.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 48, true, true); } @Test public void shouldDecodeECDSA512JOSE() throws Exception { ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); //Without padding byte[] joseSignature = createJOSESignature(66, false, false); byte[] derSignature = algorithm512.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 66, false, false); //With R padding joseSignature = createJOSESignature(66, true, false); derSignature = algorithm512.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 66, true, false); //With S padding joseSignature = createJOSESignature(66, false, true); derSignature = algorithm512.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 66, false, true); //With both paddings joseSignature = createJOSESignature(66, true, true); derSignature = algorithm512.JOSEToDER(joseSignature); assertValidDERSignature(derSignature, 66, true, true); } @Test public void shouldDecodeECDSA512DER() throws Exception { ECDSAAlgorithm algorithm512 = (ECDSAAlgorithm) Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); //Without padding byte[] derSignature = createDERSignature(66, false, false); byte[] joseSignature = algorithm512.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 66, false, false); //With R padding derSignature = createDERSignature(66, true, false); joseSignature = algorithm512.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 66, true, false); //With S padding derSignature = createDERSignature(66, false, true); joseSignature = algorithm512.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 66, false, true); //With both paddings derSignature = createDERSignature(66, true, true); joseSignature = algorithm512.DERToJOSE(derSignature); assertValidJOSESignature(joseSignature, 66, true, true); } //Test Helpers static void assertValidJOSESignature(byte[] joseSignature, int numberSize, boolean withRPadding, boolean withSPadding) { Assert.assertThat(joseSignature, is(Matchers.notNullValue())); Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); Assert.assertThat(joseSignature.length, is(numberSize * 2)); byte[] rCopy = Arrays.copyOfRange(joseSignature, 0, numberSize); byte[] sCopy = Arrays.copyOfRange(joseSignature, numberSize, numberSize * 2); byte[] rNumber = new byte[numberSize]; byte[] sNumber = new byte[numberSize]; Arrays.fill(rNumber, (byte) 0x11); Arrays.fill(sNumber, (byte) 0x22); if (withRPadding) { rNumber[0] = (byte) 0; } if (withSPadding) { sNumber[0] = (byte) 0; } Assert.assertThat(Arrays.equals(rNumber, rCopy), is(true)); Assert.assertThat(Arrays.equals(sNumber, sCopy), is(true)); } static byte[] createDERSignature(int numberSize, boolean withRPadding, boolean withSPadding) { Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); int rLength = withRPadding ? numberSize - 1 : numberSize; int sLength = withSPadding ? numberSize - 1 : numberSize; int totalLength = 2 + (2 + rLength) + (2 + sLength); byte[] rNumber = new byte[rLength]; byte[] sNumber = new byte[sLength]; Arrays.fill(rNumber, (byte) 0x11); Arrays.fill(sNumber, (byte) 0x22); byte[] derSignature; int offset = 0; if (totalLength > 0x7f) { totalLength++; derSignature = new byte[totalLength]; //Start sequence and sign derSignature[offset++] = (byte) 0x30; derSignature[offset++] = (byte) 0x81; } else { derSignature = new byte[totalLength]; //Start sequence derSignature[offset++] = (byte) 0x30; } //Sequence length derSignature[offset++] = (byte) (totalLength - offset); //R number derSignature[offset++] = (byte) 0x02; derSignature[offset++] = (byte) rLength; System.arraycopy(rNumber, 0, derSignature, offset, rLength); offset += rLength; //S number derSignature[offset++] = (byte) 0x02; derSignature[offset++] = (byte) sLength; System.arraycopy(sNumber, 0, derSignature, offset, sLength); return derSignature; } static byte[] createJOSESignature(int numberSize, boolean withRPadding, boolean withSPadding) { Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); byte[] rNumber = new byte[numberSize]; byte[] sNumber = new byte[numberSize]; Arrays.fill(rNumber, (byte) 0x11); Arrays.fill(sNumber, (byte) 0x22); if (withRPadding) { rNumber[0] = (byte) 0; } if (withSPadding) { sNumber[0] = (byte) 0; } byte[] joseSignature = new byte[numberSize * 2]; System.arraycopy(rNumber, 0, joseSignature, 0, numberSize); System.arraycopy(sNumber, 0, joseSignature, numberSize, numberSize); return joseSignature; } static void assertValidDERSignature(byte[] derSignature, int numberSize, boolean withRPadding, boolean withSPadding) { Assert.assertThat(derSignature, is(Matchers.notNullValue())); Assert.assertThat(numberSize, is(IsIn.oneOf(32, 48, 66))); int rLength = withRPadding ? numberSize - 1 : numberSize; int sLength = withSPadding ? numberSize - 1 : numberSize; int totalLength = 2 + (2 + rLength) + (2 + sLength); int offset = 0; //Start sequence Assert.assertThat(derSignature[offset++], is((byte) 0x30)); if (totalLength > 0x7f) { //Add sign before sequence length totalLength++; Assert.assertThat(derSignature[offset++], is((byte) 0x81)); } //Sequence length Assert.assertThat(derSignature[offset++], is((byte) (totalLength - offset))); //R number Assert.assertThat(derSignature[offset++], is((byte) 0x02)); Assert.assertThat(derSignature[offset++], is((byte) rLength)); byte[] rCopy = Arrays.copyOfRange(derSignature, offset, offset + rLength); offset += rLength; //S number Assert.assertThat(derSignature[offset++], is((byte) 0x02)); Assert.assertThat(derSignature[offset++], is((byte) sLength)); byte[] sCopy = Arrays.copyOfRange(derSignature, offset, offset + sLength); byte[] rNumber = new byte[rLength]; byte[] sNumber = new byte[sLength]; Arrays.fill(rNumber, (byte) 0x11); Arrays.fill(sNumber, (byte) 0x22); Assert.assertThat(Arrays.equals(rNumber, rCopy), is(true)); Assert.assertThat(Arrays.equals(sNumber, sCopy), is(true)); Assert.assertThat(derSignature.length, is(totalLength)); } @Test public void shouldBeEqualSignatureMethodDecodeResults() throws Exception { // signatures are not deterministic in value, so instead of directly comparing the signatures, // check that both sign(..) methods can be used to create a jwt which can be // verified Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); String header = "eyJhbGciOiJFUzI1NiJ9"; String payload = "eyJpc3MiOiJhdXRoMCJ9"; byte[] headerBytes = header.getBytes(StandardCharsets.UTF_8); byte[] payloadBytes = payload.getBytes(StandardCharsets.UTF_8); ByteArrayOutputStream bout = new ByteArrayOutputStream(); bout.write(headerBytes); bout.write('.'); bout.write(payloadBytes); String jwtSignature1 = Base64.encodeBase64URLSafeString(algorithm.sign(bout.toByteArray())); String jwt1 = String.format("%s.%s.%s", header, payload, jwtSignature1); algorithm.verify(JWT.decode(jwt1)); String jwtSignature2 = Base64.encodeBase64URLSafeString(algorithm.sign(headerBytes, payloadBytes)); String jwt2 = String.format("%s.%s.%s", header, payload, jwtSignature2); algorithm.verify(JWT.decode(jwt2)); } /** * Test deprecated signing method error handling. * * @see {@linkplain #shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull} * @throws Exception expected exception */ @Test public void shouldFailOnECDSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() throws Exception { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); exception.expectCause(hasMessage(is("The given Private Key is null."))); ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKey()).thenReturn(null); Algorithm algorithm = Algorithm.ECDSA256(provider); algorithm.sign(new byte[0]); } }