Only available RSA key sizes should be shown in admin console

Closes #16437
This commit is contained in:
mposolda 2023-01-23 14:42:43 +01:00 committed by Marek Posolda
parent 29888dbf1a
commit 16888eaeab
9 changed files with 58 additions and 19 deletions

View file

@ -15,7 +15,6 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters; import java.security.cert.CollectionCertStoreParameters;
import java.security.spec.ECParameterSpec; import java.security.spec.ECParameterSpec;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@ -124,4 +123,11 @@ public interface CryptoProvider {
* @return decorated factory * @return decorated factory
*/ */
SSLSocketFactory wrapFactoryForTruststore(SSLSocketFactory delegate); SSLSocketFactory wrapFactoryForTruststore(SSLSocketFactory delegate);
/**
* @return Allowed key sizes of RSA key modulus, which this cryptoProvider supports
*/
default String[] getSupportedRsaKeySizes() {
return new String[] {"1024", "2048", "4096"};
}
} }

View file

@ -14,4 +14,10 @@ public class Fips1402StrictCryptoProvider extends FIPS1402Provider {
static { static {
System.setProperty("org.bouncycastle.fips.approved_only", Boolean.TRUE.toString()); System.setProperty("org.bouncycastle.fips.approved_only", Boolean.TRUE.toString());
} }
@Override
public String[] getSupportedRsaKeySizes() {
// RSA key of 1024 bits not supported in BCFIPS approved mode
return new String[] {"2048", "4096"};
}
} }

View file

@ -78,7 +78,7 @@ public abstract class AbstractGeneratedRsaKeyProviderFactory extends AbstractRsa
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel model) throws ComponentValidationException { public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel model) throws ComponentValidationException {
super.validateConfiguration(session, realm, model); super.validateConfiguration(session, realm, model);
ConfigurationValidationHelper.check(model).checkList(Attributes.KEY_SIZE_PROPERTY, false); ConfigurationValidationHelper.check(model).checkList(Attributes.KEY_SIZE_PROPERTY.get(), false);
int size = model.get(Attributes.KEY_SIZE_KEY, 2048); int size = model.get(Attributes.KEY_SIZE_KEY, 2048);
@ -103,6 +103,10 @@ public abstract class AbstractGeneratedRsaKeyProviderFactory extends AbstractRsa
keyPair = KeyUtils.generateRsaKeyPair(size); keyPair = KeyUtils.generateRsaKeyPair(size);
model.put(Attributes.PRIVATE_KEY_KEY, PemUtils.encodeKey(keyPair.getPrivate())); model.put(Attributes.PRIVATE_KEY_KEY, PemUtils.encodeKey(keyPair.getPrivate()));
} catch (Throwable t) { } catch (Throwable t) {
getLogger().warnf("Failed to generate keys for key provider '%s' in realm '%s'. Details: %s", model.getName(), realm.getName(), t.getMessage());
if (getLogger().isDebugEnabled()) {
getLogger().debug(t.getMessage(), t);
}
throw new ComponentValidationException("Failed to generate keys", t); throw new ComponentValidationException("Failed to generate keys", t);
} }
@ -114,6 +118,10 @@ public abstract class AbstractGeneratedRsaKeyProviderFactory extends AbstractRsa
Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, realm.getName()); Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, realm.getName());
model.put(Attributes.CERTIFICATE_KEY, PemUtils.encodeCertificate(certificate)); model.put(Attributes.CERTIFICATE_KEY, PemUtils.encodeCertificate(certificate));
} catch (Throwable t) { } catch (Throwable t) {
getLogger().warnf("Failed to generate certificate for key provider '%s' in realm '%s'. Details: %s", model.getName(), realm.getName(), t.getMessage());
if (getLogger().isDebugEnabled()) {
getLogger().debug(t.getMessage(), t);
}
throw new ComponentValidationException("Failed to generate certificate", t); throw new ComponentValidationException("Failed to generate certificate", t);
} }
} }

View file

@ -17,6 +17,9 @@
package org.keycloak.keys; package org.keycloak.keys;
import java.util.function.Supplier;
import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.crypto.Algorithm; import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.KeyUse; import org.keycloak.crypto.KeyUse;
import org.keycloak.jose.jwe.JWEConstants; import org.keycloak.jose.jwe.JWEConstants;
@ -45,7 +48,8 @@ public interface Attributes {
ProviderConfigProperty CERTIFICATE_PROPERTY = new ProviderConfigProperty(CERTIFICATE_KEY, "X509 Certificate", "X509 Certificate encoded in PEM format", FILE_TYPE, null); ProviderConfigProperty CERTIFICATE_PROPERTY = new ProviderConfigProperty(CERTIFICATE_KEY, "X509 Certificate", "X509 Certificate encoded in PEM format", FILE_TYPE, null);
String KEY_SIZE_KEY = "keySize"; String KEY_SIZE_KEY = "keySize";
ProviderConfigProperty KEY_SIZE_PROPERTY = new ProviderConfigProperty(KEY_SIZE_KEY, "Key size", "Size for the generated keys", LIST_TYPE, "2048", "1024", "2048", "4096"); Supplier<ProviderConfigProperty> KEY_SIZE_PROPERTY = () -> new ProviderConfigProperty(KEY_SIZE_KEY, "Key size", "Size for the generated keys", LIST_TYPE, "2048",
CryptoIntegration.getProvider().getSupportedRsaKeySizes());
String KEY_USE = "keyUse"; String KEY_USE = "keyUse";
ProviderConfigProperty KEY_USE_PROPERTY = new ProviderConfigProperty(KEY_USE, "Key use", "Whether the key should be used for signing or encryption.", LIST_TYPE, ProviderConfigProperty KEY_USE_PROPERTY = new ProviderConfigProperty(KEY_USE, "Key use", "Whether the key should be used for signing or encryption.", LIST_TYPE,

View file

@ -37,11 +37,6 @@ public class GeneratedRsaEncKeyProviderFactory extends AbstractGeneratedRsaKeyPr
private static final String HELP_TEXT = "Generates RSA keys for key encryption and creates a self-signed certificate"; private static final String HELP_TEXT = "Generates RSA keys for key encryption and creates a self-signed certificate";
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
.property(Attributes.KEY_SIZE_PROPERTY)
.property(Attributes.RS_ENC_ALGORITHM_PROPERTY)
.build();
@Override @Override
public KeyProvider create(KeycloakSession session, ComponentModel model) { public KeyProvider create(KeycloakSession session, ComponentModel model) {
model.put(Attributes.KEY_USE, KeyUse.ENC.name()); model.put(Attributes.KEY_USE, KeyUse.ENC.name());
@ -55,7 +50,10 @@ public class GeneratedRsaEncKeyProviderFactory extends AbstractGeneratedRsaKeyPr
@Override @Override
public List<ProviderConfigProperty> getConfigProperties() { public List<ProviderConfigProperty> getConfigProperties() {
return CONFIG_PROPERTIES; return AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
.property(Attributes.KEY_SIZE_PROPERTY.get())
.property(Attributes.RS_ENC_ALGORITHM_PROPERTY)
.build();
} }
@Override @Override

View file

@ -37,11 +37,6 @@ public class GeneratedRsaKeyProviderFactory extends AbstractGeneratedRsaKeyProvi
private static final String HELP_TEXT = "Generates RSA signature keys and creates a self-signed certificate"; private static final String HELP_TEXT = "Generates RSA signature keys and creates a self-signed certificate";
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
.property(Attributes.KEY_SIZE_PROPERTY)
.property(Attributes.RS_ALGORITHM_PROPERTY)
.build();
@Override @Override
public KeyProvider create(KeycloakSession session, ComponentModel model) { public KeyProvider create(KeycloakSession session, ComponentModel model) {
if (model.getConfig().get(Attributes.KEY_USE) == null) { if (model.getConfig().get(Attributes.KEY_USE) == null) {
@ -58,7 +53,10 @@ public class GeneratedRsaKeyProviderFactory extends AbstractGeneratedRsaKeyProvi
@Override @Override
public List<ProviderConfigProperty> getConfigProperties() { public List<ProviderConfigProperty> getConfigProperties() {
return CONFIG_PROPERTIES; return AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
.property(Attributes.KEY_SIZE_PROPERTY.get())
.property(Attributes.RS_ALGORITHM_PROPERTY)
.build();
} }
@Override @Override

View file

@ -992,6 +992,7 @@ For running testsuite with server using BCFIPS approved mode, those additional p
-Dauth.server.fips.mode=strict \ -Dauth.server.fips.mode=strict \
-Dauth.server.supported.keystore.types=BCFKS \ -Dauth.server.supported.keystore.types=BCFKS \
-Dauth.server.keystore.type=bcfks -Dauth.server.keystore.type=bcfks
-Dauth.server.supported.rsa.key.sizes=2048,4096
``` ```
The log should contain `KeycloakFipsSecurityProvider` mentioning "Approved mode". Something like: The log should contain `KeycloakFipsSecurityProvider` mentioning "Approved mode". Something like:
``` ```

View file

@ -19,11 +19,17 @@ package org.keycloak.testsuite.admin;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Version; import org.keycloak.common.Version;
import org.keycloak.keys.Attributes;
import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
import org.keycloak.keys.KeyProvider;
import org.keycloak.representations.idm.ComponentTypeRepresentation;
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.info.ProviderRepresentation; import org.keycloak.representations.info.ProviderRepresentation;
import org.keycloak.representations.info.ServerInfoRepresentation; import org.keycloak.representations.info.ServerInfoRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.KeystoreUtils;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -59,11 +65,21 @@ public class ServerInfoTest extends AbstractKeycloakTest {
assertNotNull(info.getMemoryInfo()); assertNotNull(info.getMemoryInfo());
assertNotNull(info.getSystemInfo()); assertNotNull(info.getSystemInfo());
assertNotNull(info.getCryptoInfo()); assertNotNull(info.getCryptoInfo());
String expectedSupportedKeystoreTypes = System.getProperty("auth.server.supported.keystore.types"); Assert.assertNames(info.getCryptoInfo().getSupportedKeystoreTypes(), KeystoreUtils.getSupportedKeystoreTypes());
if (expectedSupportedKeystoreTypes == null) {
fail("Property 'auth.server.supported.keystore.types' not set"); String expectedSupportedRsaKeySizes = System.getProperty("auth.server.supported.rsa.key.sizes");
if (expectedSupportedRsaKeySizes == null || expectedSupportedRsaKeySizes.trim().isEmpty()) {
fail("Property 'auth.server.supported.rsa.key.sizes' not set");
} }
Assert.assertNames(info.getCryptoInfo().getSupportedKeystoreTypes(), expectedSupportedKeystoreTypes.split(",")); ComponentTypeRepresentation rsaGeneratedProviderInfo = info.getComponentTypes().get(KeyProvider.class.getName())
.stream()
.filter(componentType -> GeneratedRsaKeyProviderFactory.ID.equals(componentType.getId()))
.findFirst().orElseThrow(() -> new RuntimeException("Not found provider with ID 'rsa-generated'"));
ConfigPropertyRepresentation keySizeRep = rsaGeneratedProviderInfo.getProperties()
.stream()
.filter(configProp -> Attributes.KEY_SIZE_KEY.equals(configProp.getName()))
.findFirst().orElseThrow(() -> new RuntimeException("Not found provider with ID 'rsa-generated'"));
Assert.assertNames(keySizeRep.getOptions(), expectedSupportedRsaKeySizes.split(","));
assertEquals(Version.VERSION, info.getSystemInfo().getVersion()); assertEquals(Version.VERSION, info.getSystemInfo().getVersion());
assertNotNull(info.getSystemInfo().getServerTime()); assertNotNull(info.getSystemInfo().getServerTime());

View file

@ -265,6 +265,7 @@
<auth.server.quarkus.cluster.config>local</auth.server.quarkus.cluster.config> <auth.server.quarkus.cluster.config>local</auth.server.quarkus.cluster.config>
<auth.server.fips.mode>disabled</auth.server.fips.mode> <auth.server.fips.mode>disabled</auth.server.fips.mode>
<auth.server.supported.keystore.types>JKS,PKCS12,BCFKS</auth.server.supported.keystore.types> <auth.server.supported.keystore.types>JKS,PKCS12,BCFKS</auth.server.supported.keystore.types>
<auth.server.supported.rsa.key.sizes>1024,2048,4096</auth.server.supported.rsa.key.sizes>
</properties> </properties>
<build> <build>
@ -690,6 +691,7 @@
<auth.server.fips.mode>${auth.server.fips.mode}</auth.server.fips.mode> <auth.server.fips.mode>${auth.server.fips.mode}</auth.server.fips.mode>
<auth.server.fips.keystore.type>${auth.server.fips.keystore.type}</auth.server.fips.keystore.type> <auth.server.fips.keystore.type>${auth.server.fips.keystore.type}</auth.server.fips.keystore.type>
<auth.server.supported.keystore.types>${auth.server.supported.keystore.types}</auth.server.supported.keystore.types> <auth.server.supported.keystore.types>${auth.server.supported.keystore.types}</auth.server.supported.keystore.types>
<auth.server.supported.rsa.key.sizes>${auth.server.supported.rsa.key.sizes}</auth.server.supported.rsa.key.sizes>
<!-- <!--
~ Used for Wildfly Elytron 1.13.0.CR3+ RESTEasy client SSL truststore configuration. ~ Used for Wildfly Elytron 1.13.0.CR3+ RESTEasy client SSL truststore configuration.