HADOOP-17609. Make SM4 support optional for OpenSSL native code. (#3019)

Reviewed-by: Steve Loughran <stevel@apache.org>
Reviewed-by: Wei-Chiu Chuang <weichiu@apache.org>
This commit is contained in:
Masatake Iwasaki 2024-08-08 21:03:05 +09:00 committed by GitHub
parent b189ef8197
commit 2a50911734
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 60 additions and 11 deletions

View File

@ -178,6 +178,20 @@ private static Transform tokenizeTransformation(String transformation)
return new Transform(parts[0], parts[1], parts[2]); return new Transform(parts[0], parts[1], parts[2]);
} }
public static boolean isSupported(CipherSuite suite) {
Transform transform;
int algMode;
int padding;
try {
transform = tokenizeTransformation(suite.getName());
algMode = AlgMode.get(transform.alg, transform.mode);
padding = Padding.get(transform.padding);
} catch (NoSuchAlgorithmException|NoSuchPaddingException e) {
return false;
}
return isSupportedSuite(algMode, padding);
}
/** /**
* Initialize this cipher with a key and IV. * Initialize this cipher with a key and IV.
* *
@ -298,5 +312,7 @@ private native int doFinal(long context, ByteBuffer output, int offset,
private native void clean(long ctx, long engineNum); private native void clean(long ctx, long engineNum);
private native static boolean isSupportedSuite(int alg, int padding);
public native static String getLibraryName(); public native static String getLibraryName();
} }

View File

@ -41,6 +41,10 @@ public OpensslSm4CtrCryptoCodec() {
if (loadingFailureReason != null) { if (loadingFailureReason != null) {
throw new RuntimeException(loadingFailureReason); throw new RuntimeException(loadingFailureReason);
} }
if (!OpensslCipher.isSupported(CipherSuite.SM4_CTR_NOPADDING)) {
throw new RuntimeException("The OpenSSL native library is built without SM4 CTR support");
}
} }
@Override @Override

View File

@ -232,7 +232,10 @@ JNIEXPORT void JNICALL Java_org_apache_hadoop_crypto_OpensslCipher_initIDs
#endif #endif
loadAesCtr(env); loadAesCtr(env);
#if !defined(OPENSSL_NO_SM4)
loadSm4Ctr(env); loadSm4Ctr(env);
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10101001L #if OPENSSL_VERSION_NUMBER >= 0x10101001L
int ret = dlsym_OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); int ret = dlsym_OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
if(!ret) { if(!ret) {
@ -245,7 +248,7 @@ JNIEXPORT void JNICALL Java_org_apache_hadoop_crypto_OpensslCipher_initIDs
if (jthr) { if (jthr) {
(*env)->DeleteLocalRef(env, jthr); (*env)->DeleteLocalRef(env, jthr);
THROW(env, "java/lang/UnsatisfiedLinkError", \ THROW(env, "java/lang/UnsatisfiedLinkError", \
"Cannot find AES-CTR/SM4-CTR support, is your version of Openssl new enough?"); "Cannot find AES-CTR support, is your version of OpenSSL new enough?");
return; return;
} }
} }
@ -554,3 +557,24 @@ JNIEXPORT jstring JNICALL Java_org_apache_hadoop_crypto_OpensslCipher_getLibrary
} }
#endif #endif
} }
JNIEXPORT jboolean JNICALL Java_org_apache_hadoop_crypto_OpensslCipher_isSupportedSuite
(JNIEnv *env, jclass clazz, jint alg, jint padding)
{
if (padding != NOPADDING) {
return JNI_FALSE;
}
if (alg == AES_CTR && (dlsym_EVP_aes_256_ctr != NULL && dlsym_EVP_aes_128_ctr != NULL)) {
return JNI_TRUE;
}
if (alg == SM4_CTR) {
#if OPENSSL_VERSION_NUMBER >= 0x10101001L && !defined(OPENSSL_NO_SM4)
if (dlsym_EVP_sm4_ctr != NULL) {
return JNI_TRUE;
}
#endif
}
return JNI_FALSE;
}

View File

@ -106,31 +106,21 @@ public void testJceAesCtrCryptoCodec() throws Exception {
@Test(timeout=120000) @Test(timeout=120000)
public void testJceSm4CtrCryptoCodec() throws Exception { public void testJceSm4CtrCryptoCodec() throws Exception {
GenericTestUtils.assumeInNativeProfile();
if (!NativeCodeLoader.buildSupportsOpenssl()) {
LOG.warn("Skipping test since openSSL library not loaded");
Assume.assumeTrue(false);
}
conf.set(HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_KEY, "SM4/CTR/NoPadding"); conf.set(HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_KEY, "SM4/CTR/NoPadding");
conf.set(HADOOP_SECURITY_CRYPTO_CODEC_CLASSES_SM4_CTR_NOPADDING_KEY, conf.set(HADOOP_SECURITY_CRYPTO_CODEC_CLASSES_SM4_CTR_NOPADDING_KEY,
JceSm4CtrCryptoCodec.class.getName()); JceSm4CtrCryptoCodec.class.getName());
conf.set(HADOOP_SECURITY_CRYPTO_JCE_PROVIDER_KEY, conf.set(HADOOP_SECURITY_CRYPTO_JCE_PROVIDER_KEY,
BouncyCastleProvider.PROVIDER_NAME); BouncyCastleProvider.PROVIDER_NAME);
Assert.assertEquals(null, OpensslCipher.getLoadingFailureReason());
cryptoCodecTest(conf, seed, 0, cryptoCodecTest(conf, seed, 0,
jceSm4CodecClass, jceSm4CodecClass, iv); jceSm4CodecClass, jceSm4CodecClass, iv);
cryptoCodecTest(conf, seed, count, cryptoCodecTest(conf, seed, count,
jceSm4CodecClass, jceSm4CodecClass, iv); jceSm4CodecClass, jceSm4CodecClass, iv);
cryptoCodecTest(conf, seed, count,
jceSm4CodecClass, opensslSm4CodecClass, iv);
// Overflow test, IV: xx xx xx xx xx xx xx xx ff ff ff ff ff ff ff ff // Overflow test, IV: xx xx xx xx xx xx xx xx ff ff ff ff ff ff ff ff
for(int i = 0; i < 8; i++) { for(int i = 0; i < 8; i++) {
iv[8 + i] = (byte) 0xff; iv[8 + i] = (byte) 0xff;
} }
cryptoCodecTest(conf, seed, count, cryptoCodecTest(conf, seed, count,
jceSm4CodecClass, jceSm4CodecClass, iv); jceSm4CodecClass, jceSm4CodecClass, iv);
cryptoCodecTest(conf, seed, count,
jceSm4CodecClass, opensslSm4CodecClass, iv);
} }
@Test(timeout=120000) @Test(timeout=120000)
@ -164,6 +154,7 @@ public void testOpensslSm4CtrCryptoCodec() throws Exception {
LOG.warn("Skipping test since openSSL library not loaded"); LOG.warn("Skipping test since openSSL library not loaded");
Assume.assumeTrue(false); Assume.assumeTrue(false);
} }
Assume.assumeTrue(OpensslCipher.isSupported(CipherSuite.SM4_CTR_NOPADDING));
conf.set(HADOOP_SECURITY_CRYPTO_JCE_PROVIDER_KEY, conf.set(HADOOP_SECURITY_CRYPTO_JCE_PROVIDER_KEY,
BouncyCastleProvider.PROVIDER_NAME); BouncyCastleProvider.PROVIDER_NAME);
Assert.assertEquals(null, OpensslCipher.getLoadingFailureReason()); Assert.assertEquals(null, OpensslCipher.getLoadingFailureReason());
@ -181,6 +172,8 @@ public void testOpensslSm4CtrCryptoCodec() throws Exception {
opensslSm4CodecClass, opensslSm4CodecClass, iv); opensslSm4CodecClass, opensslSm4CodecClass, iv);
cryptoCodecTest(conf, seed, count, cryptoCodecTest(conf, seed, count,
opensslSm4CodecClass, jceSm4CodecClass, iv); opensslSm4CodecClass, jceSm4CodecClass, iv);
cryptoCodecTest(conf, seed, count,
jceSm4CodecClass, opensslSm4CodecClass, iv);
} }
private void cryptoCodecTest(Configuration conf, int seed, int count, private void cryptoCodecTest(Configuration conf, int seed, int count,

View File

@ -21,6 +21,7 @@
import org.apache.hadoop.crypto.random.OsSecureRandom; import org.apache.hadoop.crypto.random.OsSecureRandom;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic; import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.test.GenericTestUtils; import org.apache.hadoop.test.GenericTestUtils;
import org.junit.Assume;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -40,6 +41,7 @@ public class TestCryptoStreamsWithOpensslSm4CtrCryptoCodec
@BeforeClass @BeforeClass
public static void init() throws Exception { public static void init() throws Exception {
GenericTestUtils.assumeInNativeProfile(); GenericTestUtils.assumeInNativeProfile();
Assume.assumeTrue(OpensslCipher.isSupported(CipherSuite.SM4_CTR_NOPADDING));
Configuration conf = new Configuration(); Configuration conf = new Configuration();
conf.set(HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_KEY, "SM4/CTR/NoPadding"); conf.set(HADOOP_SECURITY_CRYPTO_CIPHER_SUITE_KEY, "SM4/CTR/NoPadding");
conf.set(HADOOP_SECURITY_CRYPTO_CODEC_CLASSES_SM4_CTR_NOPADDING_KEY, conf.set(HADOOP_SECURITY_CRYPTO_CODEC_CLASSES_SM4_CTR_NOPADDING_KEY,

View File

@ -107,4 +107,14 @@ public void testDoFinalArguments() throws Exception {
"Direct buffer is required", e); "Direct buffer is required", e);
} }
} }
@Test(timeout=120000)
public void testIsSupportedSuite() throws Exception {
Assume.assumeTrue("Skipping due to falilure of loading OpensslCipher.",
OpensslCipher.getLoadingFailureReason() == null);
Assert.assertFalse("Unknown suite must not be supported.",
OpensslCipher.isSupported(CipherSuite.UNKNOWN));
Assert.assertTrue("AES/CTR/NoPadding is not an optional suite.",
OpensslCipher.isSupported(CipherSuite.AES_CTR_NOPADDING));
}
} }