From dad4477995de9c4955eab1f5d73d92680e90056d Mon Sep 17 00:00:00 2001 From: mposolda Date: Mon, 2 Sep 2024 15:53:03 +0200 Subject: [PATCH] Remove keycloak-core and keycloak-crypto-default from SAML galleon feature pack and upgrade them to Java 17 closes #32586 Signed-off-by: mposolda --- adapters/saml/core/pom.xml | 5 - .../adapters/saml/config/PemUtils.java | 144 ++++++++++++++++++ .../config/parsers/DeploymentBuilder.java | 4 +- core/pom.xml | 34 ----- .../keycloak/jose/jwk/AbstractJWKParser.java | 9 +- .../org/keycloak/jose/jwk/JWKBuilder.java | 66 +++++++- .../java/org/keycloak/jose/jwk/JWKParser.java | 86 ++++++++++- .../org/keycloak/jose/jwk/JWKBuilder.java | 108 ------------- .../org/keycloak/jose/jwk/JWKParser.java | 124 --------------- crypto/default/pom.xml | 5 - .../keycloak/keycloak-core/main/module.xml | 38 ----- .../keycloak-crypto-default/main/module.xml | 40 ----- .../main/module.xml | 3 +- .../org/keycloak/jose/jwk/ServerJWKTest.java | 2 +- 14 files changed, 294 insertions(+), 374 deletions(-) create mode 100644 adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/PemUtils.java delete mode 100644 core/src/main/java16/org/keycloak/jose/jwk/JWKBuilder.java delete mode 100644 core/src/main/java16/org/keycloak/jose/jwk/JWKParser.java delete mode 100755 distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml delete mode 100644 distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml diff --git a/adapters/saml/core/pom.xml b/adapters/saml/core/pom.xml index 49c5a82b80..ac557d8297 100755 --- a/adapters/saml/core/pom.xml +++ b/adapters/saml/core/pom.xml @@ -61,11 +61,6 @@ keycloak-common provided - - org.keycloak - keycloak-crypto-default - test - org.jboss.logging jboss-logging diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/PemUtils.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/PemUtils.java new file mode 100644 index 0000000000..d60d1e3922 --- /dev/null +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/PemUtils.java @@ -0,0 +1,144 @@ +/* + * 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.adapters.saml.config; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import org.keycloak.common.util.Base64; +import org.keycloak.common.util.BouncyIntegration; +import org.keycloak.common.util.PemException; + +/** + * Fork of the PemUtils from common module to avoid dependency on keycloak-crypto-default + */ +public class PemUtils { + + /** + * Decode a X509 Certificate from a PEM string + * + * @param cert + * @return + * @throws Exception + */ + public static X509Certificate decodeCertificate(String cert) { + if (cert == null) { + return null; + } + + try { + byte[] der = pemToDer(cert); + ByteArrayInputStream bis = new ByteArrayInputStream(der); + return decodeCertificate(bis); + } catch (Exception e) { + throw new PemException(e); + } + } + + + /** + * Decode a Public Key from a PEM string + * + * @param pem + * @return + * @throws Exception + */ + public static PublicKey decodePublicKey(String pem) { + if (pem == null) { + return null; + } + + try { + byte[] der = pemToDer(pem); + return decodePublicKey(der, "RSA"); + } catch (Exception e) { + throw new PemException(e); + } + } + + /** + * Decode a Private Key from a PEM string + * + * @param pem + * @return + * @throws Exception + */ + public static PrivateKey decodePrivateKey(String pem){ + if (pem == null) { + return null; + } + + try { + byte[] der = pemToDer(pem); + return decodePrivateKey(der); + } catch (Exception e) { + throw new PemException(e); + } + } + + private static byte[] pemToDer(String pem) { + try { + pem = removeBeginEnd(pem); + return Base64.decode(pem); + } catch (IOException ioe) { + throw new PemException(ioe); + } + } + + private static String removeBeginEnd(String pem) { + pem = pem.replaceAll("-----BEGIN (.*)-----", ""); + pem = pem.replaceAll("-----END (.*)----", ""); + pem = pem.replaceAll("\r\n", ""); + pem = pem.replaceAll("\n", ""); + return pem.trim(); + } + + private static PrivateKey decodePrivateKey(byte[] der) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException { + PKCS8EncodedKeySpec spec = + new PKCS8EncodedKeySpec(der); + KeyFactory kf = KeyFactory.getInstance("RSA", BouncyIntegration.PROVIDER); + return kf.generatePrivate(spec); + } + + private static X509Certificate decodeCertificate(InputStream is) throws Exception { + CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyIntegration.PROVIDER); + X509Certificate cert = (X509Certificate) cf.generateCertificate(is); + is.close(); + return cert; + } + + private static PublicKey decodePublicKey(byte[] der, String type) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException { + X509EncodedKeySpec spec = + new X509EncodedKeySpec(der); + KeyFactory kf = KeyFactory.getInstance("RSA", BouncyIntegration.PROVIDER); + return kf.generatePublic(spec); + } +} diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java index 27336b5cd8..298d0b2b8d 100755 --- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java +++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java @@ -24,10 +24,9 @@ import org.keycloak.adapters.saml.SamlDeployment; import org.keycloak.adapters.saml.config.IDP; import org.keycloak.adapters.saml.config.Key; import org.keycloak.adapters.saml.config.KeycloakSamlAdapter; +import org.keycloak.adapters.saml.config.PemUtils; import org.keycloak.adapters.saml.config.SP; -import org.keycloak.common.crypto.CryptoIntegration; import org.keycloak.common.enums.SslRequired; -import org.keycloak.common.util.PemUtils; import org.keycloak.saml.SignatureAlgorithm; import org.keycloak.saml.common.exceptions.ParsingException; @@ -58,7 +57,6 @@ public class DeploymentBuilder { protected static Logger log = Logger.getLogger(DeploymentBuilder.class); public SamlDeployment build(InputStream xml, ResourceLoader resourceLoader) throws ParsingException { - CryptoIntegration.init(DeploymentBuilder.class.getClassLoader()); DefaultSamlDeployment deployment = new DefaultSamlDeployment(); DefaultSamlDeployment.DefaultIDP defaultIDP = new DefaultSamlDeployment.DefaultIDP(); DefaultSamlDeployment.DefaultSingleSignOnService sso = new DefaultSamlDeployment.DefaultSingleSignOnService(); diff --git a/core/pom.xml b/core/pom.xml index 61068466a4..fc63273305 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -32,8 +32,6 @@ - - 11 ${maven.build.timestamp} yyyy-MM-dd HH:mm @@ -74,38 +72,6 @@ - - - jdk-16 - - [16,) - - - - - maven-compiler-plugin - - - compile-java16 - compile - - compile - - - 16 - - ${project.basedir}/src/main/java16 - - true - - - - - - - - - diff --git a/core/src/main/java/org/keycloak/jose/jwk/AbstractJWKParser.java b/core/src/main/java/org/keycloak/jose/jwk/AbstractJWKParser.java index b45e3a0bca..1e089626db 100644 --- a/core/src/main/java/org/keycloak/jose/jwk/AbstractJWKParser.java +++ b/core/src/main/java/org/keycloak/jose/jwk/AbstractJWKParser.java @@ -41,10 +41,13 @@ public abstract class AbstractJWKParser { } public PublicKey toPublicKey() { + if (jwk == null) { + throw new IllegalStateException("Not possible to convert to the publicKey. The jwk is not set"); + } String keyType = jwk.getKeyType(); - if (keyType.equals(KeyType.RSA)) { + if (KeyType.RSA.equals(keyType)) { return createRSAPublicKey(); - } else if (keyType.equals(KeyType.EC)) { + } else if (KeyType.EC.equals(keyType)) { return createECPublicKey(); } else { @@ -87,7 +90,7 @@ public abstract class AbstractJWKParser { } try { - + ECPoint point = new ECPoint(x, y); ECParameterSpec params = CryptoIntegration.getProvider().createECParams(name); ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params); diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWKBuilder.java b/core/src/main/java/org/keycloak/jose/jwk/JWKBuilder.java index 282dbd3d80..c3943c742a 100644 --- a/core/src/main/java/org/keycloak/jose/jwk/JWKBuilder.java +++ b/core/src/main/java/org/keycloak/jose/jwk/JWKBuilder.java @@ -17,15 +17,27 @@ package org.keycloak.jose.jwk; -import org.keycloak.crypto.KeyUse; - +import java.math.BigInteger; import java.security.Key; +import java.security.interfaces.EdECPublicKey; +import java.security.spec.EdECPoint; +import java.util.Arrays; +import java.util.Optional; + +import org.keycloak.common.util.Base64Url; +import org.keycloak.common.util.KeyUtils; +import org.keycloak.crypto.Algorithm; +import org.keycloak.crypto.KeyType; +import org.keycloak.crypto.KeyUse; /** * @author Stian Thorgersen */ public class JWKBuilder extends AbstractJWKBuilder { + private JWKBuilder() { + } + public static JWKBuilder create() { return new JWKBuilder(); } @@ -42,13 +54,55 @@ public class JWKBuilder extends AbstractJWKBuilder { @Override public JWK okp(Key key) { - // not supported if jdk vesion < 17 - throw new UnsupportedOperationException("EdDSA algorithms not supported in this JDK version"); + return okp(key, DEFAULT_PUBLIC_KEY_USE); } @Override public JWK okp(Key key, KeyUse keyUse) { - // not supported if jdk version < 17 - throw new UnsupportedOperationException("EdDSA algorithms not supported in this JDK version"); + EdECPublicKey eddsaPublicKey = (EdECPublicKey) key; + + OKPPublicJWK k = new OKPPublicJWK(); + + String kid = this.kid != null ? this.kid : KeyUtils.createKeyId(key); + + k.setKeyId(kid); + k.setKeyType(KeyType.OKP); + k.setAlgorithm(algorithm); + k.setPublicKeyUse(keyUse == null ? DEFAULT_PUBLIC_KEY_USE.getSpecName() : keyUse.getSpecName()); + k.setCrv(eddsaPublicKey.getParams().getName()); + + Optional x = edPublicKeyInJwkRepresentation(eddsaPublicKey); + k.setX(x.orElse("")); + + return k; } + + private Optional edPublicKeyInJwkRepresentation(EdECPublicKey eddsaPublicKey) { + EdECPoint edEcPoint = eddsaPublicKey.getPoint(); + BigInteger yCoordinate = edEcPoint.getY(); + + // JWK representation "x" of a public key + int bytesLength = 0; + if (Algorithm.Ed25519.equals(eddsaPublicKey.getParams().getName())) { + bytesLength = 32; + } else if (Algorithm.Ed448.equals(eddsaPublicKey.getParams().getName())) { + bytesLength = 57; + } else { + return Optional.ofNullable(null); + } + + // consider the case where yCoordinate.toByteArray() is less than bytesLength due to relatively small value of y-coordinate. + byte[] yCoordinateLittleEndianBytes = new byte[bytesLength]; + + // convert big endian representation of BigInteger to little endian representation of JWK representation (RFC 8032,8027) + yCoordinateLittleEndianBytes = Arrays.copyOf(reverseBytes(yCoordinate.toByteArray()), bytesLength); + + // set a parity of x-coordinate to the most significant bit of the last octet (RFC 8032, 8037) + if (edEcPoint.isXOdd()) { + yCoordinateLittleEndianBytes[yCoordinateLittleEndianBytes.length - 1] |= -128; // 0b10000000 + } + + return Optional.ofNullable(Base64Url.encode(yCoordinateLittleEndianBytes)); + } + } diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java index 13820e30d5..cfa646cbbd 100755 --- a/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java +++ b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java @@ -17,6 +17,18 @@ package org.keycloak.jose.jwk; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.EdECPoint; +import java.security.spec.EdECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.NamedParameterSpec; + +import org.keycloak.common.util.Base64Url; +import org.keycloak.crypto.Algorithm; +import org.keycloak.crypto.KeyType; import org.keycloak.util.JsonSerialization; /** @@ -24,17 +36,17 @@ import org.keycloak.util.JsonSerialization; */ public class JWKParser extends AbstractJWKParser { - protected JWKParser() { - } - - public JWKParser(JWK jwk) { - this.jwk = jwk; + private JWKParser() { } public static JWKParser create() { return new JWKParser(); } + public JWKParser(JWK jwk) { + this.jwk = jwk; + } + public static JWKParser create(JWK jwk) { return new JWKParser(jwk); } @@ -48,4 +60,68 @@ public class JWKParser extends AbstractJWKParser { } } + @Override + public PublicKey toPublicKey() { + if (jwk == null) { + throw new IllegalStateException("Not possible to convert to the publicKey. The jwk is not set"); + } + String keyType = jwk.getKeyType(); + if (KeyType.RSA.equals(keyType)) { + return createRSAPublicKey(); + } else if (KeyType.EC.equals(keyType)) { + return createECPublicKey(); + } else if (KeyType.OKP.equals(keyType)) { + return createOKPPublicKey(); + } else { + throw new RuntimeException("Unsupported keyType " + keyType); + } + } + + private PublicKey createOKPPublicKey() { + String x = (String) jwk.getOtherClaims().get(OKPPublicJWK.X); + String crv = (String) jwk.getOtherClaims().get(OKPPublicJWK.CRV); + // JWK representation "x" of a public key + int bytesLength = 0; + if (Algorithm.Ed25519.equals(crv)) { + bytesLength = 32; + } else if (Algorithm.Ed448.equals(crv)) { + bytesLength = 57; + } else { + throw new RuntimeException("Invalid JWK representation of OKP type algorithm"); + } + + byte[] decodedX = Base64Url.decode(x); + if (decodedX.length != bytesLength) { + throw new RuntimeException("Invalid JWK representation of OKP type public key"); + } + + // x-coordinate's parity check shown by MSB(bit) of MSB(byte) of decoded "x": 1 is odd, 0 is even + boolean isOddX = false; + if ((decodedX[decodedX.length - 1] & -128) != 0) { // 0b10000000 + isOddX = true; + } + + // MSB(bit) of MSB(byte) showing x-coodinate's parity is set to 0 + decodedX[decodedX.length - 1] &= 127; // 0b01111111 + + // both x and y-coordinate in twisted Edwards curve are always 0 or natural number + BigInteger y = new BigInteger(1, JWKBuilder.reverseBytes(decodedX)); + NamedParameterSpec spec = new NamedParameterSpec(crv); + EdECPoint ep = new EdECPoint(isOddX, y); + EdECPublicKeySpec keySpec = new EdECPublicKeySpec(spec, ep); + + PublicKey publicKey = null; + try { + publicKey = KeyFactory.getInstance(crv).generatePublic(keySpec); + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + return publicKey; + } + + @Override + public boolean isKeyTypeSupported(String keyType) { + return (RSAPublicJWK.RSA.equals(keyType) || ECPublicJWK.EC.equals(keyType) || OKPPublicJWK.OKP.equals(keyType)); + } + } diff --git a/core/src/main/java16/org/keycloak/jose/jwk/JWKBuilder.java b/core/src/main/java16/org/keycloak/jose/jwk/JWKBuilder.java deleted file mode 100644 index 808eb84607..0000000000 --- a/core/src/main/java16/org/keycloak/jose/jwk/JWKBuilder.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2023 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.jose.jwk; - -import java.math.BigInteger; -import java.security.Key; -import java.security.interfaces.EdECPublicKey; -import java.security.spec.EdECPoint; -import java.util.Arrays; -import java.util.Optional; - -import org.keycloak.common.util.Base64Url; -import org.keycloak.common.util.KeyUtils; -import org.keycloak.crypto.Algorithm; -import org.keycloak.crypto.KeyType; -import org.keycloak.crypto.KeyUse; - -/** - * @author Takashi Norimatsu - */ -public class JWKBuilder extends AbstractJWKBuilder { - - private JWKBuilder() { - } - - public static JWKBuilder create() { - return new JWKBuilder(); - } - - public JWKBuilder kid(String kid) { - this.kid = kid; - return this; - } - - public JWKBuilder algorithm(String algorithm) { - this.algorithm = algorithm; - return this; - } - - @Override - public JWK okp(Key key) { - return okp(key, DEFAULT_PUBLIC_KEY_USE); - } - - @Override - public JWK okp(Key key, KeyUse keyUse) { - EdECPublicKey eddsaPublicKey = (EdECPublicKey) key; - - OKPPublicJWK k = new OKPPublicJWK(); - - String kid = this.kid != null ? this.kid : KeyUtils.createKeyId(key); - - k.setKeyId(kid); - k.setKeyType(KeyType.OKP); - k.setAlgorithm(algorithm); - k.setPublicKeyUse(keyUse == null ? DEFAULT_PUBLIC_KEY_USE.getSpecName() : keyUse.getSpecName()); - k.setCrv(eddsaPublicKey.getParams().getName()); - - Optional x = edPublicKeyInJwkRepresentation(eddsaPublicKey); - k.setX(x.orElse("")); - - return k; - } - - private Optional edPublicKeyInJwkRepresentation(EdECPublicKey eddsaPublicKey) { - EdECPoint edEcPoint = eddsaPublicKey.getPoint(); - BigInteger yCoordinate = edEcPoint.getY(); - - // JWK representation "x" of a public key - int bytesLength = 0; - if (Algorithm.Ed25519.equals(eddsaPublicKey.getParams().getName())) { - bytesLength = 32; - } else if (Algorithm.Ed448.equals(eddsaPublicKey.getParams().getName())) { - bytesLength = 57; - } else { - return Optional.ofNullable(null); - } - - // consider the case where yCoordinate.toByteArray() is less than bytesLength due to relatively small value of y-coordinate. - byte[] yCoordinateLittleEndianBytes = new byte[bytesLength]; - - // convert big endian representation of BigInteger to little endian representation of JWK representation (RFC 8032,8027) - yCoordinateLittleEndianBytes = Arrays.copyOf(reverseBytes(yCoordinate.toByteArray()), bytesLength); - - // set a parity of x-coordinate to the most significant bit of the last octet (RFC 8032, 8037) - if (edEcPoint.isXOdd()) { - yCoordinateLittleEndianBytes[yCoordinateLittleEndianBytes.length - 1] |= -128; // 0b10000000 - } - - return Optional.ofNullable(Base64Url.encode(yCoordinateLittleEndianBytes)); - } - -} diff --git a/core/src/main/java16/org/keycloak/jose/jwk/JWKParser.java b/core/src/main/java16/org/keycloak/jose/jwk/JWKParser.java deleted file mode 100644 index c99cf5d287..0000000000 --- a/core/src/main/java16/org/keycloak/jose/jwk/JWKParser.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2023 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.jose.jwk; - -import java.math.BigInteger; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.spec.EdECPoint; -import java.security.spec.EdECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.NamedParameterSpec; - -import org.keycloak.common.util.Base64Url; -import org.keycloak.crypto.Algorithm; -import org.keycloak.crypto.KeyType; -import org.keycloak.util.JsonSerialization; - -/** - * @author Takashi Norimatsu - */ -public class JWKParser extends AbstractJWKParser { - - private JWKParser() { - } - - public static JWKParser create() { - return new JWKParser(); - } - - public JWKParser(JWK jwk) { - this.jwk = jwk; - } - - public static JWKParser create(JWK jwk) { - return new JWKParser(jwk); - } - - public JWKParser parse(String jwk) { - try { - this.jwk = JsonSerialization.mapper.readValue(jwk, JWK.class); - return this; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public PublicKey toPublicKey() { - String keyType = jwk.getKeyType(); - if (keyType.equals(KeyType.RSA)) { - return createRSAPublicKey(); - } else if (keyType.equals(KeyType.EC)) { - return createECPublicKey(); - } else if (keyType.equals(KeyType.OKP)) { - return createOKPPublicKey(); - } else { - throw new RuntimeException("Unsupported keyType " + keyType); - } - } - - private PublicKey createOKPPublicKey() { - String x = (String) jwk.getOtherClaims().get(OKPPublicJWK.X); - String crv = (String) jwk.getOtherClaims().get(OKPPublicJWK.CRV); - // JWK representation "x" of a public key - int bytesLength = 0; - if (Algorithm.Ed25519.equals(crv)) { - bytesLength = 32; - } else if (Algorithm.Ed448.equals(crv)) { - bytesLength = 57; - } else { - throw new RuntimeException("Invalid JWK representation of OKP type algorithm"); - } - - byte[] decodedX = Base64Url.decode(x); - if (decodedX.length != bytesLength) { - throw new RuntimeException("Invalid JWK representation of OKP type public key"); - } - - // x-coordinate's parity check shown by MSB(bit) of MSB(byte) of decoded "x": 1 is odd, 0 is even - boolean isOddX = false; - if ((decodedX[decodedX.length - 1] & -128) != 0) { // 0b10000000 - isOddX = true; - } - - // MSB(bit) of MSB(byte) showing x-coodinate's parity is set to 0 - decodedX[decodedX.length - 1] &= 127; // 0b01111111 - - // both x and y-coordinate in twisted Edwards curve are always 0 or natural number - BigInteger y = new BigInteger(1, JWKBuilder.reverseBytes(decodedX)); - NamedParameterSpec spec = new NamedParameterSpec(crv); - EdECPoint ep = new EdECPoint(isOddX, y); - EdECPublicKeySpec keySpec = new EdECPublicKeySpec(spec, ep); - - PublicKey publicKey = null; - try { - publicKey = KeyFactory.getInstance(crv).generatePublic(keySpec); - } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - return publicKey; - } - - @Override - public boolean isKeyTypeSupported(String keyType) { - return (RSAPublicJWK.RSA.equals(keyType) || ECPublicJWK.EC.equals(keyType) || OKPPublicJWK.OKP.equals(keyType)); - } - -} \ No newline at end of file diff --git a/crypto/default/pom.xml b/crypto/default/pom.xml index 33aa7a62f5..2b0cf1fb23 100644 --- a/crypto/default/pom.xml +++ b/crypto/default/pom.xml @@ -30,11 +30,6 @@ Keycloak Crypto Default - - - 11 - - org.keycloak diff --git a/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml b/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml deleted file mode 100755 index ae472c9dba..0000000000 --- a/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-core/main/module.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml b/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml deleted file mode 100644 index 341f074123..0000000000 --- a/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-crypto-default/main/module.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-saml-adapter-core/main/module.xml b/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-saml-adapter-core/main/module.xml index 4cf0bae3aa..465593f379 100755 --- a/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-saml-adapter-core/main/module.xml +++ b/distribution/galleon-feature-packs/saml-adapter-galleon-pack/src/main/resources/modules/system/add-ons/keycloak/org/keycloak/keycloak-saml-adapter-core/main/module.xml @@ -35,10 +35,9 @@ - - + diff --git a/services/src/test/java/org/keycloak/jose/jwk/ServerJWKTest.java b/services/src/test/java/org/keycloak/jose/jwk/ServerJWKTest.java index ec0a51b6ad..5420cf72db 100644 --- a/services/src/test/java/org/keycloak/jose/jwk/ServerJWKTest.java +++ b/services/src/test/java/org/keycloak/jose/jwk/ServerJWKTest.java @@ -42,7 +42,7 @@ import org.keycloak.util.JsonSerialization; * * @author Takashi Norimatsu */ -public abstract class ServerJWKTest { +public class ServerJWKTest { @ClassRule public static CryptoInitRule cryptoInitRule = new CryptoInitRule();