JWSBuilder when used directly with AsymmetricSignatureSignerContext produces non compliant ECDSA signed JWT (#29333)

closes #29309 

Signed-off-by: Francis Pouatcha <francis.pouatcha@adorsys.com>
This commit is contained in:
Francis Pouatcha 2024-05-27 12:45:42 +01:00 committed by GitHub
parent 5a68056f2a
commit 2683c0a7d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 117 additions and 13 deletions

View file

@ -0,0 +1,36 @@
/*
* 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;
import org.keycloak.common.VerificationException;
public class ECDSASignatureVerifierContext extends AsymmetricSignatureVerifierContext{
public ECDSASignatureVerifierContext(KeyWrapper key) {
super(key);
}
@Override
public boolean verify(byte[] data, byte[] signature) throws VerificationException {
try {
int expectedSize = ECDSAAlgorithm.getSignatureLength(getAlgorithm());
byte[] derSignature = ECDSAAlgorithm.concatenatedRSToASN1DER(signature, expectedSize);
return super.verify(data, derSignature);
} catch (Exception e) {
throw new VerificationException("Verification failed", e);
}
}
}

View file

@ -30,16 +30,18 @@ import java.security.spec.ECPublicKeySpec;
import java.util.HashMap;
import java.util.Map;
import org.junit.ClassRule;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.crypto.AsymmetricSignatureSignerContext;
import org.keycloak.crypto.AsymmetricSignatureVerifierContext;
import org.keycloak.crypto.ECDSASignatureSignerContext;
import org.keycloak.crypto.ECDSASignatureVerifierContext;
import org.keycloak.crypto.KeyUse;
import org.keycloak.crypto.KeyWrapper;
import org.keycloak.crypto.SignatureSignerContext;
import org.keycloak.crypto.SignatureVerifierContext;
import com.fasterxml.jackson.databind.JsonNode;
import org.keycloak.rule.CryptoInitRule;
/**
* Import test-settings from:
@ -208,7 +210,7 @@ public class TestSettings {
keyWrapper.setType(keyPair.getPublic().getAlgorithm());
keyWrapper.setUse(KeyUse.SIG);
keyWrapper.setKid(kid);
return new AsymmetricSignatureSignerContext(keyWrapper);
return new ECDSASignatureSignerContext(keyWrapper);
}
private static SignatureVerifierContext getSignatureVerifierContext(PublicKey publicKey, String algorithm,
@ -219,7 +221,7 @@ public class TestSettings {
keyWrapper.setType(publicKey.getAlgorithm());
keyWrapper.setUse(KeyUse.SIG);
keyWrapper.setKid(kid);
return new AsymmetricSignatureVerifierContext(keyWrapper);
return new ECDSASignatureVerifierContext(keyWrapper);
}
private static final Map<String, String> ECDSA_CURVE_2_SPECS_NAMES = new HashMap<>();

View file

@ -16,13 +16,12 @@
*/
package org.keycloak.sdjwt.sdjwtvp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.VerificationException;
import org.keycloak.rule.CryptoInitRule;
import org.keycloak.sdjwt.DisclosureSpec;
import org.keycloak.sdjwt.IssuerSignedJWT;
import org.keycloak.sdjwt.SdJwt;
@ -30,13 +29,17 @@ import org.keycloak.sdjwt.TestSettings;
import org.keycloak.sdjwt.TestUtils;
import org.keycloak.sdjwt.vp.SdJwtVP;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
*/
public class SdJwtVPTest {
public abstract class SdJwtVPTest {
@ClassRule
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
// Additional tests can be written to cover edge cases, error conditions,
// and any other functionality specific to the SdJwt class.
@Test

View file

@ -1 +1 @@
eyJhbGciOiJFUzI1NiIsInR5cCIgOiAidmMrc2Qtand0Iiwia2lkIiA6ICJkb2Mtc2lnbmVyLTA1LTI1LTIwMjIifQ.eyJfc2QiOlsiSHZyS1g2ZlBWMHY5S195Q1ZGQmlMRkhzTWF4Y0RfMTE0RW02VlQ4eDFsZyJdLCJfc2RfYWxnIjoic2hhLTI1NiIsInN1YiI6IjZjNWMwYTQ5LWI1ODktNDMxZC1iYWU3LTIxOTEyMmE5ZWMyYyIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwiaWF0IjoxNjgzMDAwMDAwLCJleHAiOjE4ODMwMDAwMDB9.MEQCICde3GkeuNWixUiD3zk5F9OMGD2HJW6Lmo4waWkVXDddAiByEPMrOn8aE9Tf33_J3SIiVBEhQNthU58O7D0Y1Xywcg~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgInN0cmVldF9hZGRyZXNzIiwgIlNjaHVsc3RyLiAxMiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImxvY2FsaXR5IiwgIlNjaHVscGZvcnRhIl0~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgInJlZ2lvbiIsICJTYWNoc2VuLUFuaGFsdCJd~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgImNvdW50cnkiLCAiREUiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgImFkZHJlc3MiLCB7Il9zZCI6IFsiNnZoOWJxLXpTNEdLTV83R3BnZ1ZiWXp6dTZvT0dYcm1OVkdQSFA3NVVkMCIsICI5Z2pWdVh0ZEZST0NnUnJ0TmNHVVhtRjY1cmRlemlfNkVyX2o3NmttWXlNIiwgIktVUkRQaDRaQzE5LTN0aXotRGYzOVY4ZWlkeTFvVjNhM0gxRGEyTjBnODgiLCAiV045cjlkQ0JKOEhUQ3NTMmpLQVN4VGpFeVc1bTV4NjVfWl8ycm8yamZYTSJdfV0~
eyJraWQiOiJkb2Mtc2lnbmVyLTA1LTI1LTIwMjIiLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJfc2QiOlsiSHZyS1g2ZlBWMHY5S195Q1ZGQmlMRkhzTWF4Y0RfMTE0RW02VlQ4eDFsZyJdLCJfc2RfYWxnIjoic2hhLTI1NiIsInN1YiI6IjZjNWMwYTQ5LWI1ODktNDMxZC1iYWU3LTIxOTEyMmE5ZWMyYyIsImlzcyI6Imh0dHBzOi8vaXNzdWVyLmV4YW1wbGUuY29tIiwiaWF0IjoxNjgzMDAwMDAwLCJleHAiOjE4ODMwMDAwMDB9.Bhhy9eDenyBCsh9F064pxs5SK0Tbfc0o4xXlzmYv50qODKShpfsiC8__W1SXrF687JsbXmbD7VA5Db7iMoPwbg~WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgInN0cmVldF9hZGRyZXNzIiwgIlNjaHVsc3RyLiAxMiJd~WyJlbHVWNU9nM2dTTklJOEVZbnN4QV9BIiwgImxvY2FsaXR5IiwgIlNjaHVscGZvcnRhIl0~WyI2SWo3dE0tYTVpVlBHYm9TNXRtdlZBIiwgInJlZ2lvbiIsICJTYWNoc2VuLUFuaGFsdCJd~WyJlSThaV205UW5LUHBOUGVOZW5IZGhRIiwgImNvdW50cnkiLCAiREUiXQ~WyJRZ19PNjR6cUF4ZTQxMmExMDhpcm9BIiwgImFkZHJlc3MiLCB7Il9zZCI6IFsiNnZoOWJxLXpTNEdLTV83R3BnZ1ZiWXp6dTZvT0dYcm1OVkdQSFA3NVVkMCIsICI5Z2pWdVh0ZEZST0NnUnJ0TmNHVVhtRjY1cmRlemlfNkVyX2o3NmttWXlNIiwgIktVUkRQaDRaQzE5LTN0aXotRGYzOVY4ZWlkeTFvVjNhM0gxRGEyTjBnODgiLCAiV045cjlkQ0JKOEhUQ3NTMmpLQVN4VGpFeVc1bTV4NjVfWl8ycm8yamZYTSJdfV0~

View file

@ -0,0 +1,36 @@
/*
* 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.def.test;
import org.junit.Assume;
import org.junit.Before;
import org.keycloak.common.util.Environment;
import org.keycloak.sdjwt.sdjwtvp.SdJwtVPTest;
/**
* Test with default security provider and non-fips bouncycastle
*
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
*/
public class DefaultCryptoSdJwtVPTest extends SdJwtVPTest {
@Before
public void before() {
// Run this test just if java is not in FIPS mode
Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
}
}

View file

@ -0,0 +1,27 @@
/*
* 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.elytron.test;
import org.keycloak.sdjwt.sdjwtvp.SdJwtVPTest;
/**
* Test with Elytron provider
*
* @author <a href="mailto:francis.pouatcha@adorsys.com">Francis Pouatcha</a>
*/
public class ElytronCryptoSdJwtVPTest extends SdJwtVPTest {
}