KEYCLOAK-19723 Existing ECDSA key provider's key pair is not regenerated when its curve is changed on Admin Console
This commit is contained in:
parent
5740e158e3
commit
d0493b4306
2 changed files with 85 additions and 3 deletions
|
@ -28,7 +28,10 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.provider.ConfigurationValidationHelper;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.List;
|
||||
|
||||
public class GeneratedEcdsaKeyProviderFactory extends AbstractEcdsaKeyProviderFactory {
|
||||
|
@ -103,7 +106,7 @@ public class GeneratedEcdsaKeyProviderFactory extends AbstractEcdsaKeyProviderFa
|
|||
generateKeys(model, ecInNistRep);
|
||||
logger.debugv("Generated keys for {0}", realm.getName());
|
||||
} else {
|
||||
String currentEc = model.get(ECDSA_ELLIPTIC_CURVE_KEY);
|
||||
String currentEc = getCurveFromPublicKey(model.getConfig().getFirst(GeneratedEcdsaKeyProviderFactory.ECDSA_PUBLIC_KEY_KEY));
|
||||
if (!ecInNistRep.equals(currentEc)) {
|
||||
generateKeys(model, ecInNistRep);
|
||||
logger.debugv("Elliptic Curve changed, generating new keys for {0}", realm.getName());
|
||||
|
@ -123,4 +126,14 @@ public class GeneratedEcdsaKeyProviderFactory extends AbstractEcdsaKeyProviderFa
|
|||
}
|
||||
}
|
||||
|
||||
private String getCurveFromPublicKey(String publicEcdsaKeyBase64Encoded) {
|
||||
try {
|
||||
KeyFactory kf = KeyFactory.getInstance("EC");
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.decode(publicEcdsaKeyBase64Encoded));
|
||||
ECPublicKey ecKey = (ECPublicKey) kf.generatePublic(publicKeySpec);
|
||||
return "P-" + ecKey.getParams().getCurve().getField().getFieldSize();
|
||||
} catch (Throwable t) {
|
||||
throw new ComponentValidationException("Failed to get EC from its public key", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,13 @@
|
|||
package org.keycloak.testsuite.keys;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
@ -28,8 +32,10 @@ import javax.ws.rs.core.Response;
|
|||
import org.jboss.arquillian.graphene.page.Page;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.common.util.Base64;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.crypto.KeyType;
|
||||
import org.keycloak.keys.AbstractEcdsaKeyProviderFactory;
|
||||
import org.keycloak.keys.GeneratedEcdsaKeyProviderFactory;
|
||||
import org.keycloak.keys.KeyProvider;
|
||||
import org.keycloak.representations.idm.ComponentRepresentation;
|
||||
|
@ -87,8 +93,8 @@ public class GeneratedEcdsaKeyProviderTest extends AbstractKeycloakTest {
|
|||
// NIST.FIPS.186-4 Koblitz Curve over Binary Field
|
||||
unsupportedEc("K-163");
|
||||
}
|
||||
|
||||
private void supportedEc(String ecInNistRep) {
|
||||
|
||||
private String supportedEc(String ecInNistRep) {
|
||||
long priority = System.currentTimeMillis();
|
||||
|
||||
ComponentRepresentation rep = createRep("valid", GeneratedEcdsaKeyProviderFactory.ID);
|
||||
|
@ -127,6 +133,8 @@ public class GeneratedEcdsaKeyProviderTest extends AbstractKeycloakTest {
|
|||
assertEquals(id, key.getProviderId());
|
||||
assertEquals(KeyType.EC, key.getType());
|
||||
assertEquals(priority, key.getProviderPriority());
|
||||
|
||||
return id; // created key's component id
|
||||
}
|
||||
|
||||
private void unsupportedEc(String ecInNistRep) {
|
||||
|
@ -152,6 +160,60 @@ public class GeneratedEcdsaKeyProviderTest extends AbstractKeycloakTest {
|
|||
assertEquals(isEcAccepted, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeCurveFromP256ToP384() throws Exception {
|
||||
changeCurve("P-256", "P-384");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeCurveFromP384ToP521() throws Exception {
|
||||
changeCurve("P-384", "P-521");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeCurveFromP521ToP256() throws Exception {
|
||||
changeCurve("P-521", "P-256");
|
||||
}
|
||||
|
||||
private void changeCurve(String FromEcInNistRep, String ToEcInNistRep) throws Exception {
|
||||
String keyComponentId = supportedEc(FromEcInNistRep);
|
||||
KeysMetadataRepresentation keys = adminClient.realm(TEST_REALM_NAME).keys().getKeyMetadata();
|
||||
KeysMetadataRepresentation.KeyMetadataRepresentation originalKey = null;
|
||||
for (KeyMetadataRepresentation k : keys.getKeys()) {
|
||||
if (KeyType.EC.equals(k.getType()) && keyComponentId.equals(k.getProviderId())) {
|
||||
originalKey = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ComponentRepresentation createdRep = adminClient.realm(TEST_REALM_NAME).components().component(keyComponentId).toRepresentation();
|
||||
createdRep.getConfig().putSingle(ECDSA_ELLIPTIC_CURVE_KEY, ToEcInNistRep);
|
||||
adminClient.realm(TEST_REALM_NAME).components().component(keyComponentId).update(createdRep);
|
||||
|
||||
createdRep = adminClient.realm(TEST_REALM_NAME).components().component(keyComponentId).toRepresentation();
|
||||
|
||||
// stands for the number of properties in the key provider config
|
||||
assertEquals(2, createdRep.getConfig().size());
|
||||
assertEquals(ToEcInNistRep, createdRep.getConfig().getFirst(ECDSA_ELLIPTIC_CURVE_KEY));
|
||||
|
||||
keys = adminClient.realm(TEST_REALM_NAME).keys().getKeyMetadata();
|
||||
KeysMetadataRepresentation.KeyMetadataRepresentation key = null;
|
||||
for (KeyMetadataRepresentation k : keys.getKeys()) {
|
||||
if (KeyType.EC.equals(k.getType()) && keyComponentId.equals(k.getProviderId())) {
|
||||
key = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotNull(key);
|
||||
|
||||
assertEquals(keyComponentId, key.getProviderId());
|
||||
assertNotEquals(originalKey.getKid(), key.getKid()); // kid is changed if key was regenerated
|
||||
assertEquals(KeyType.EC, key.getType());
|
||||
assertNotEquals(originalKey.getAlgorithm(), key.getAlgorithm());
|
||||
assertEquals(ToEcInNistRep, AbstractEcdsaKeyProviderFactory.convertAlgorithmToECDomainParmNistRep(key.getAlgorithm()));
|
||||
assertEquals(ToEcInNistRep, getCurveFromPublicKey(key.getPublicKey()));
|
||||
}
|
||||
|
||||
protected ComponentRepresentation createRep(String name, String providerId) {
|
||||
ComponentRepresentation rep = new ComponentRepresentation();
|
||||
rep.setName(name);
|
||||
|
@ -161,4 +223,11 @@ public class GeneratedEcdsaKeyProviderTest extends AbstractKeycloakTest {
|
|||
rep.setConfig(new MultivaluedHashMap<>());
|
||||
return rep;
|
||||
}
|
||||
|
||||
private String getCurveFromPublicKey(String publicEcdsaKeyBase64Encoded) throws Exception {
|
||||
KeyFactory kf = KeyFactory.getInstance("EC");
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.decode(publicEcdsaKeyBase64Encoded));
|
||||
ECPublicKey ecKey = (ECPublicKey) kf.generatePublic(publicKeySpec);
|
||||
return "P-" + ecKey.getParams().getCurve().getField().getFieldSize();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue