diff --git a/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java b/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java index 1c53e6186cd..db8460d62c3 100644 --- a/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java +++ b/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java @@ -24,4 +24,8 @@ public class CryptoConstants { /** Name of Java security provider used with fips BouncyCastle. Should be used in FIPS environment */ public static final String BCFIPS_PROVIDER_ID = "BCFIPS"; + public static final String EC_KEY_SECP256R1 = "secp256r1"; + public static final String EC_KEY_SECP384R1 = "secp384r1"; + public static final String EC_KEY_SECP521R1 = "secp521r1"; + } diff --git a/common/src/main/java/org/keycloak/common/util/KeyUtils.java b/common/src/main/java/org/keycloak/common/util/KeyUtils.java index 14d49b5f909..bb4b067b9a0 100644 --- a/common/src/main/java/org/keycloak/common/util/KeyUtils.java +++ b/common/src/main/java/org/keycloak/common/util/KeyUtils.java @@ -25,7 +25,9 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; +import java.security.SecureRandom; import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.ECGenParameterSpec; import java.security.spec.RSAPublicKeySpec; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -72,6 +74,27 @@ public class KeyUtils { } } + public static KeyPair generateEddsaKeyPair(String curveName) { + try { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(curveName); + return keyGen.generateKeyPair(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static KeyPair generateEcKeyPair(String keySpecName) { + try { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); + SecureRandom randomGen = new SecureRandom(); + ECGenParameterSpec ecSpec = new ECGenParameterSpec(keySpecName); + keyGen.initialize(ecSpec, randomGen); + return keyGen.generateKeyPair(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + public static String createKeyId(Key key) { try { return Base64Url.encode(MessageDigest.getInstance(DEFAULT_MESSAGE_DIGEST).digest(key.getEncoded())); diff --git a/core/src/main/java/org/keycloak/crypto/ECCurve.java b/core/src/main/java/org/keycloak/crypto/ECCurve.java deleted file mode 100644 index c17819f8be1..00000000000 --- a/core/src/main/java/org/keycloak/crypto/ECCurve.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2024 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.crypto; - -public enum ECCurve { - P256, - P384, - P521; - - /** - * Convert standard EC curve names (and aliases) into this enum. - */ - public static ECCurve fromStdCrv(String crv) { - switch (crv) { - case "P-256": - case "secp256r1": - return P256; - case "P-384": - case "secp384r1": - return P384; - case "P-521": - case "secp521r1": - return P521; - default: - throw new IllegalArgumentException("Unexpected EC curve: " + crv); - } - } -} diff --git a/core/src/main/java/org/keycloak/crypto/KeyWrapper.java b/core/src/main/java/org/keycloak/crypto/KeyWrapper.java index 7e7de05cd68..0eb03a8ee3e 100644 --- a/core/src/main/java/org/keycloak/crypto/KeyWrapper.java +++ b/core/src/main/java/org/keycloak/crypto/KeyWrapper.java @@ -22,6 +22,10 @@ import java.util.ArrayList; import java.util.List; import javax.crypto.SecretKey; +import static org.keycloak.common.crypto.CryptoConstants.EC_KEY_SECP256R1; +import static org.keycloak.common.crypto.CryptoConstants.EC_KEY_SECP384R1; +import static org.keycloak.common.crypto.CryptoConstants.EC_KEY_SECP521R1; + public class KeyWrapper { private String providerId; @@ -82,6 +86,8 @@ public class KeyWrapper { *
For keys of type {@link KeyType#EC}, {@link Algorithm#ES256}, {@link Algorithm#ES384}, or {@link Algorithm#ES512} * is returned based on the curve * + *
For keys of type {@link KeyType#OKP}, {@link Algorithm#EdDSA} as that is the only value supported for that key type
+ *
* @return the algorithm set or a default based on the key type.
*/
public String getAlgorithmOrDefault() {
@@ -91,15 +97,21 @@ public class KeyWrapper {
if (curve != null) {
switch (curve) {
case "P-256":
+ case EC_KEY_SECP256R1:
return Algorithm.ES256;
case "P-384":
+ case EC_KEY_SECP384R1:
return Algorithm.ES384;
case "P-512":
+ case "P-521":
+ case EC_KEY_SECP521R1:
return Algorithm.ES512;
}
}
case KeyType.RSA:
return Algorithm.RS256;
+ case KeyType.OKP:
+ return Algorithm.EdDSA;
}
}
return algorithm;
diff --git a/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java b/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java
index eb4ee7d547a..0e7c36c0e42 100644
--- a/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java
+++ b/core/src/main/java/org/keycloak/sdjwt/IssuerSignedJWT.java
@@ -34,7 +34,6 @@ import org.keycloak.common.VerificationException;
import org.keycloak.crypto.SignatureSignerContext;
import org.keycloak.jose.jwk.JWK;
import org.keycloak.jose.jws.JWSHeader;
-import org.keycloak.sdjwt.vp.KeyBindingJWT;
import org.keycloak.util.JsonSerialization;
import com.fasterxml.jackson.databind.JsonNode;
@@ -44,6 +43,7 @@ import com.fasterxml.jackson.databind.node.LongNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import static org.keycloak.OID4VCConstants.CLAIM_NAME_CNF;
+import static org.keycloak.OID4VCConstants.CLAIM_NAME_JWK;
import static org.keycloak.OID4VCConstants.CLAIM_NAME_SD;
import static org.keycloak.OID4VCConstants.CLAIM_NAME_SD_HASH_ALGORITHM;
@@ -461,27 +461,10 @@ public class IssuerSignedJWT extends JwsToken {
return this;
}
- /**
- * this method requires the public key to be present in the keybindingJwts header as "jwk" claim
- */
- public Builder withKeyBinding(KeyBindingJWT keyBinding) {
+ public Builder withKeyBindingKey(JWK keyBinding) {
+ ObjectNode jwkNode = JsonSerialization.mapper.convertValue(keyBinding, ObjectNode.class);
ObjectNode cnf = JsonNodeFactory.instance.objectNode();
- Optional.ofNullable(keyBinding.getJwsHeader().getOtherClaims().get(OID4VCConstants.CLAIM_NAME_JWK))
- .map(map -> JsonSerialization.mapper.convertValue(map, ObjectNode.class))
- .ifPresent(jwkNode -> cnf.set(OID4VCConstants.CLAIM_NAME_JWK, jwkNode));
- if (!cnf.isEmpty()) {
- getClaims().add(new VisibleSdJwtClaim(SdJwtClaimName.of(CLAIM_NAME_CNF), cnf));
- }
- return this;
- }
-
- public Builder withKeyBinding(JWK keyBinding) {
- return withKeyBinding(JsonSerialization.mapper.convertValue(keyBinding, ObjectNode.class));
- }
-
- public Builder withKeyBinding(ObjectNode keyBinding) {
- ObjectNode cnf = JsonNodeFactory.instance.objectNode();
- cnf.set("jwk", keyBinding);
+ cnf.set(CLAIM_NAME_JWK, jwkNode);
getClaims().add(new VisibleSdJwtClaim(SdJwtClaimName.of(CLAIM_NAME_CNF), cnf));
return this;
}
diff --git a/core/src/main/java/org/keycloak/sdjwt/JwkParsingUtils.java b/core/src/main/java/org/keycloak/sdjwt/JwkParsingUtils.java
index 9bb8b56d0a5..412410c6c6f 100644
--- a/core/src/main/java/org/keycloak/sdjwt/JwkParsingUtils.java
+++ b/core/src/main/java/org/keycloak/sdjwt/JwkParsingUtils.java
@@ -19,15 +19,11 @@ package org.keycloak.sdjwt;
import java.util.Objects;
-import org.keycloak.crypto.Algorithm;
-import org.keycloak.crypto.AsymmetricSignatureVerifierContext;
-import org.keycloak.crypto.ECCurve;
-import org.keycloak.crypto.ECDSASignatureVerifierContext;
-import org.keycloak.crypto.KeyType;
import org.keycloak.crypto.KeyWrapper;
import org.keycloak.crypto.SignatureVerifierContext;
import org.keycloak.jose.jwk.JWK;
import org.keycloak.util.JWKSUtils;
+import org.keycloak.util.KeyWrapperUtil;
import com.fasterxml.jackson.databind.JsonNode;
@@ -50,7 +46,6 @@ public class JwkParsingUtils {
public static SignatureVerifierContext convertJwkToVerifierContext(JWK jwk) {
// Wrap JWK
-
KeyWrapper keyWrapper;
try {
@@ -61,39 +56,6 @@ public class JwkParsingUtils {
}
// Build verifier
-
- // KeyType.EC
- if (keyWrapper.getType().equals(KeyType.EC)) {
- if (keyWrapper.getAlgorithm() == null) {
- Objects.requireNonNull(keyWrapper.getCurve());
-
- String alg = null;
- switch (ECCurve.fromStdCrv(keyWrapper.getCurve())) {
- case P256:
- alg = Algorithm.ES256;
- break;
- case P384:
- alg = Algorithm.ES384;
- break;
- case P521:
- alg = Algorithm.ES512;
- break;
- }
-
- keyWrapper.setAlgorithm(alg);
- }
-
- return new ECDSASignatureVerifierContext(keyWrapper);
- }
-
- // KeyType.RSA
- if (keyWrapper.getType().equals(KeyType.RSA)) {
- return new AsymmetricSignatureVerifierContext(keyWrapper);
- }
-
- // KeyType is not supported
- // This is unreachable as of now given that `JWKSUtils.getKeyWrapper` will fail
- // on JWKs with key type not equal to EC or RSA.
- throw new IllegalArgumentException("Unexpected key type: " + keyWrapper.getType());
+ return KeyWrapperUtil.createSignatureVerifierContext(keyWrapper);
}
}
diff --git a/core/src/main/java/org/keycloak/util/DPoPGenerator.java b/core/src/main/java/org/keycloak/util/DPoPGenerator.java
index 9cf87832dbd..3091dd592e1 100644
--- a/core/src/main/java/org/keycloak/util/DPoPGenerator.java
+++ b/core/src/main/java/org/keycloak/util/DPoPGenerator.java
@@ -24,9 +24,6 @@ import java.security.PrivateKey;
import org.keycloak.OAuth2Constants;
import org.keycloak.common.util.SecretGenerator;
import org.keycloak.common.util.Time;
-import org.keycloak.crypto.AsymmetricSignatureSignerContext;
-import org.keycloak.crypto.ECDSASignatureSignerContext;
-import org.keycloak.crypto.KeyType;
import org.keycloak.crypto.KeyUse;
import org.keycloak.crypto.KeyWrapper;
import org.keycloak.crypto.SignatureSignerContext;
@@ -93,23 +90,11 @@ public class DPoPGenerator {
}
private String sign(JWSHeader jwsHeader, DPoP dpop, KeyWrapper keyWrapper) {
- SignatureSignerContext sigCtx = createSignatureSignerContext(keyWrapper);
+ SignatureSignerContext sigCtx = KeyWrapperUtil.createSignatureSignerContext(keyWrapper);
return new JWSBuilder()
.header(jwsHeader)
.jsonContent(dpop)
.sign(sigCtx);
}
-
- private SignatureSignerContext createSignatureSignerContext(KeyWrapper keyWrapper) {
- switch (keyWrapper.getType()) {
- case KeyType.EC:
- return new ECDSASignatureSignerContext(keyWrapper);
- case KeyType.RSA:
- case KeyType.OKP:
- return new AsymmetricSignatureSignerContext(keyWrapper);
- default:
- throw new IllegalArgumentException("No signer provider for key algorithm type " + keyWrapper.getType());
- }
- }
}
diff --git a/core/src/main/java/org/keycloak/util/KeyWrapperUtil.java b/core/src/main/java/org/keycloak/util/KeyWrapperUtil.java
new file mode 100644
index 00000000000..d821c30eceb
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/KeyWrapperUtil.java
@@ -0,0 +1,40 @@
+package org.keycloak.util;
+
+import org.keycloak.crypto.AsymmetricSignatureSignerContext;
+import org.keycloak.crypto.AsymmetricSignatureVerifierContext;
+import org.keycloak.crypto.ECDSASignatureSignerContext;
+import org.keycloak.crypto.ECDSASignatureVerifierContext;
+import org.keycloak.crypto.KeyType;
+import org.keycloak.crypto.KeyWrapper;
+import org.keycloak.crypto.SignatureSignerContext;
+import org.keycloak.crypto.SignatureVerifierContext;
+
+public class KeyWrapperUtil {
+
+ public static SignatureSignerContext createSignatureSignerContext(KeyWrapper keyWrapper) {
+ switch (keyWrapper.getType()) {
+ case KeyType.EC:
+ return new ECDSASignatureSignerContext(keyWrapper);
+ case KeyType.RSA:
+ case KeyType.OKP:
+ return new AsymmetricSignatureSignerContext(keyWrapper);
+ default:
+ throw new IllegalArgumentException("No signer provider for key algorithm type " + keyWrapper.getType());
+ }
+ }
+
+ public static SignatureVerifierContext createSignatureVerifierContext(KeyWrapper keyWrapper) {
+ switch (keyWrapper.getType()) {
+ case KeyType.EC:
+ return new ECDSASignatureVerifierContext(keyWrapper);
+ case KeyType.RSA:
+ case KeyType.OKP:
+ return new AsymmetricSignatureVerifierContext(keyWrapper);
+ default:
+ throw new IllegalArgumentException("No signer provider for key algorithm type " + keyWrapper.getType());
+ }
+ }
+
+ private KeyWrapperUtil() {
+ }
+}
diff --git a/core/src/test/java/org/keycloak/sdjwt/SdJwtCreationAndSigningTest.java b/core/src/test/java/org/keycloak/sdjwt/SdJwtCreationAndSigningTest.java
index 78e33f0b68c..d2aa794f8a3 100644
--- a/core/src/test/java/org/keycloak/sdjwt/SdJwtCreationAndSigningTest.java
+++ b/core/src/test/java/org/keycloak/sdjwt/SdJwtCreationAndSigningTest.java
@@ -20,9 +20,6 @@ package org.keycloak.sdjwt;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.SecureRandom;
-import java.security.spec.ECGenParameterSpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
@@ -55,6 +52,8 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
+import static org.keycloak.common.crypto.CryptoConstants.EC_KEY_SECP256R1;
+
/**
* @author Pascal Knueppel
* @since 13.11.2025
@@ -185,10 +184,10 @@ public abstract class SdJwtCreationAndSigningTest {
public void testCreateSdJwtWithKeybindingJwt() throws Exception {
final String authorizationServerUrl = "https://example.com";
- KeyWrapper issuerKeyPair = toKeyWrapper(createEcKey());
+ KeyWrapper issuerKeyPair = toKeyWrapper(KeyUtils.generateEcKeyPair(EC_KEY_SECP256R1));
JWK issuerJwk = JWKBuilder.create().ec(issuerKeyPair.getPublicKey());
- KeyWrapper holderKeyPair = toKeyWrapper(createEcKey());
+ KeyWrapper holderKeyPair = toKeyWrapper(KeyUtils.generateEcKeyPair(EC_KEY_SECP256R1));
JWK holderKeybindingKey = JWKBuilder.create().ec(holderKeyPair.getPublicKey());
SignatureSignerContext issuerSignerContext = new ECDSASignatureSignerContext(issuerKeyPair);
@@ -225,7 +224,7 @@ public abstract class SdJwtCreationAndSigningTest {
.withKid(issuerJwk.getKeyId())
/* body */
.withClaims(disclosures, disclosureSpec)
- .withKeyBinding(holderKeybindingKey)
+ .withKeyBindingKey(holderKeybindingKey)
.withIat(iat)
.withNbf(nbf)
.withExp(exp)
@@ -384,16 +383,6 @@ public abstract class SdJwtCreationAndSigningTest {
}
}
- public KeyPair createEcKey() {
- try {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
- kpg.initialize(new ECGenParameterSpec("secp521r1"), new SecureRandom());
- return kpg.generateKeyPair();
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
public KeyWrapper toKeyWrapper(KeyPair keyPair) {
KeyWrapper keyWrapper = new KeyWrapper();
keyWrapper.setKid(KeyUtils.createKeyId(keyPair.getPublic()));
diff --git a/core/src/test/java/org/keycloak/sdjwt/TestSettings.java b/core/src/test/java/org/keycloak/sdjwt/TestSettings.java
index 4034b73c84f..005e1eb3215 100644
--- a/core/src/test/java/org/keycloak/sdjwt/TestSettings.java
+++ b/core/src/test/java/org/keycloak/sdjwt/TestSettings.java
@@ -19,10 +19,8 @@ package org.keycloak.sdjwt;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
-import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
-import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
@@ -193,10 +191,7 @@ public class TestSettings {
// generate key spec
private static ECParameterSpec generateEcdsaKeySpec(String paramSpecName) {
try {
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
- ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(paramSpecName);
- keyPairGenerator.initialize(ecGenParameterSpec);
- KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ KeyPair keyPair = KeyUtils.generateEcKeyPair(paramSpecName);
return ((java.security.interfaces.ECPublicKey) keyPair.getPublic()).getParams();
} catch (Exception e) {
throw new RuntimeException("Error obtaining ECParameterSpec for P-256 curve", e);
diff --git a/core/src/test/java/org/keycloak/sdjwt/sdjwtvp/SdJwtKeyBindingTest.java b/core/src/test/java/org/keycloak/sdjwt/sdjwtvp/SdJwtKeyBindingTest.java
new file mode 100644
index 00000000000..d4ece01b1f7
--- /dev/null
+++ b/core/src/test/java/org/keycloak/sdjwt/sdjwtvp/SdJwtKeyBindingTest.java
@@ -0,0 +1,242 @@
+package org.keycloak.sdjwt.sdjwtvp;
+
+import java.security.KeyPair;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.keycloak.common.VerificationException;
+import org.keycloak.common.util.KeyUtils;
+import org.keycloak.common.util.Time;
+import org.keycloak.crypto.Algorithm;
+import org.keycloak.crypto.KeyWrapper;
+import org.keycloak.crypto.SignatureVerifierContext;
+import org.keycloak.jose.jwk.ECPublicJWK;
+import org.keycloak.jose.jwk.JWK;
+import org.keycloak.jose.jwk.JWKBuilder;
+import org.keycloak.jose.jwk.OKPPublicJWK;
+import org.keycloak.jose.jwk.RSAPublicJWK;
+import org.keycloak.rule.CryptoInitRule;
+import org.keycloak.sdjwt.DisclosureSpec;
+import org.keycloak.sdjwt.IssuerSignedJWT;
+import org.keycloak.sdjwt.IssuerSignedJwtVerificationOpts;
+import org.keycloak.sdjwt.SdJwt;
+import org.keycloak.sdjwt.SdJwtUtils;
+import org.keycloak.sdjwt.TestSettings;
+import org.keycloak.sdjwt.TestUtils;
+import org.keycloak.sdjwt.vp.KeyBindingJWT;
+import org.keycloak.sdjwt.vp.KeyBindingJwtVerificationOpts;
+import org.keycloak.sdjwt.vp.SdJwtVP;
+import org.keycloak.util.JWKSUtils;
+import org.keycloak.util.KeyWrapperUtil;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import static org.keycloak.OID4VCConstants.CLAIM_NAME_EXP;
+import static org.keycloak.OID4VCConstants.CLAIM_NAME_IAT;
+import static org.keycloak.OID4VCConstants.CLAIM_NAME_ISSUER;
+import static org.keycloak.OID4VCConstants.CLAIM_NAME_JWK;
+import static org.keycloak.OID4VCConstants.CLAIM_NAME_NBF;
+import static org.keycloak.common.crypto.CryptoConstants.EC_KEY_SECP256R1;
+import static org.keycloak.common.crypto.CryptoConstants.EC_KEY_SECP384R1;
+import static org.keycloak.common.crypto.CryptoConstants.EC_KEY_SECP521R1;
+import static org.keycloak.sdjwt.sdjwtvp.SdJwtVPVerificationTest.testSettings;
+
+import static org.hamcrest.CoreMatchers.is;
+
+/**
+ * Test of various algorithms and scenarios for SD-JWT key binding
+ */
+public abstract class SdJwtKeyBindingTest {
+
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
+
+ @Test
+ public void testEdDSAKeyBindingWithEd25519() throws VerificationException {
+ testKeyBinding(() -> KeyUtils.generateEddsaKeyPair(Algorithm.Ed25519),
+ keyPair -> JWKBuilder.create().okp(keyPair.getPublic()),
+ jwk -> assertEdDSAKey(jwk, Algorithm.Ed25519));
+ }
+
+ @Test
+ public void testEdDSAKeyBindingWithEd448() throws VerificationException {
+ testKeyBinding(() -> KeyUtils.generateEddsaKeyPair(Algorithm.Ed448),
+ keyPair -> JWKBuilder.create().okp(keyPair.getPublic()),
+ jwk -> assertEdDSAKey(jwk, Algorithm.Ed448));
+ }
+
+ @Test
+ public void testEc256KeyBinding() throws VerificationException {
+ testKeyBinding(() -> KeyUtils.generateEcKeyPair(EC_KEY_SECP256R1),
+ keyPair -> JWKBuilder.create().ec(keyPair.getPublic()),
+ jwk -> assertEcKey(jwk, "P-256"));
+ }
+
+ @Test
+ public void testEc384KeyBinding() throws VerificationException {
+ testKeyBinding(() -> KeyUtils.generateEcKeyPair(EC_KEY_SECP384R1),
+ keyPair -> JWKBuilder.create().ec(keyPair.getPublic()),
+ jwk -> assertEcKey(jwk, "P-384"));
+ }
+
+ @Test
+ public void testEc521KeyBinding() throws VerificationException {
+ testKeyBinding(() -> KeyUtils.generateEcKeyPair(EC_KEY_SECP521R1),
+ keyPair -> JWKBuilder.create().ec(keyPair.getPublic()),
+ jwk -> assertEcKey(jwk, "P-521"));
+ }
+
+ @Test
+ public void testRSA2048KeyBinding() throws VerificationException {
+ testKeyBinding(() -> KeyUtils.generateRsaKeyPair(2048),
+ keyPair -> JWKBuilder.create().rsa(keyPair.getPublic()),
+ jwk -> assertRsaKey(jwk));
+ }
+
+ @Test
+ public void testRSA4096KeyBinding() throws VerificationException {
+ testKeyBinding(() -> KeyUtils.generateRsaKeyPair(4096),
+ keyPair -> JWKBuilder.create().rsa(keyPair.getPublic()),
+ jwk -> assertRsaKey(jwk));
+ }
+
+ private void testKeyBinding(Supplier