JweAlgorithmProviderFuzzer.java
// Copyright 2023 the cncf-fuzzing authors
//
// 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.
//
///////////////////////////////////////////////////////////////////////////
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import javax.crypto.KeyGenerator;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.fips.FipsRSA;
import org.keycloak.crypto.def.AesKeyWrapAlgorithmProvider;
import org.keycloak.crypto.def.DefaultRsaKeyEncryption256JWEAlgorithmProvider;
import org.keycloak.crypto.elytron.ElytronRsaKeyEncryption256JWEAlgorithmProvider;
import org.keycloak.crypto.fips.FIPSAesKeyWrapAlgorithmProvider;
import org.keycloak.jose.jwe.JWEConstants;
import org.keycloak.jose.jwe.JWEKeyStorage;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
import org.keycloak.jose.jwe.enc.AesGcmJWEEncryptionProvider;
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
/**
* This fuzzer targets the encodeCek and decodeCek
* methods of different JweAlgorithm Provider
* implementation classes in the crypto package.
*
* The fuzzer randomly selects a provider in each
* iteration and either encodes or decodes a value
* specified by the fuzzer.
*/
public class JweAlgorithmProviderFuzzer {
// Set up a list of valid encryption algorithm for the JWE object
private static final String[] enc = {
JWEConstants.A128GCM, JWEConstants.A192GCM, JWEConstants.A256GCM};
private static KeyPair keyPair;
private static Key key;
public static void fuzzerInitialize() {
try {
// Initialize the base object for key management and generation
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
key = keyGenerator.generateKey();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
keyPair = generator.generateKeyPair();
} catch (NoSuchAlgorithmException e) {
// Known exception
}
}
public static void fuzzerTestOneInput(FuzzedDataProvider data) throws Exception {
try {
JWEAlgorithmProvider algorithmProvider = null;
Key encryptionKey = null;
Key decryptionKey = null;
// Randomly create an JWE Algorithm Provider instance
switch (data.consumeInt(1, 5)) {
case 1:
encryptionKey = key;
decryptionKey = key;
algorithmProvider = new AesKeyWrapAlgorithmProvider();
break;
case 2:
encryptionKey = key;
decryptionKey = key;
algorithmProvider = new org.keycloak.crypto.elytron.AesKeyWrapAlgorithmProvider();
case 3:
encryptionKey = key;
decryptionKey = key;
algorithmProvider = new FIPSAesKeyWrapAlgorithmProvider();
break;
case 4:
// TODO: make encryptionKey and decryptionKey global vars
encryptionKey = keyPair.getPublic();
decryptionKey = keyPair.getPrivate();
algorithmProvider = new DefaultRsaKeyEncryption256JWEAlgorithmProvider("RSA");
break;
case 5:
// TODO: make encryptionKey and decryptionKey global vars
encryptionKey = keyPair.getPublic();
decryptionKey = keyPair.getPrivate();
algorithmProvider = new ElytronRsaKeyEncryption256JWEAlgorithmProvider("RSA");
break;
}
// Randomly choose to encode or decode with the JWE Algorithm provider instance
if (data.consumeBoolean()) {
JWEEncryptionProvider provider =
new AesGcmJWEEncryptionProvider(data.pickValue(JweAlgorithmProviderFuzzer.enc));
JWEKeyStorage storage = new JWEKeyStorage();
storage.setEncryptionProvider(provider);
storage.setEncryptionKey(encryptionKey);
storage.setDecryptionKey(decryptionKey);
algorithmProvider.encodeCek(provider, storage, encryptionKey);
} else {
algorithmProvider.decodeCek(data.consumeRemainingAsBytes(), decryptionKey);
}
} catch (NoSuchMethodError | AssertionError e) {
// Known error
} catch (CryptoException | GeneralSecurityException | IllegalArgumentException e) {
// Known exception
}
}
}