diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/AbstractTestX509Parameterized.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/AbstractTestX509Parameterized.java
new file mode 100644
index 000000000000..821a68541358
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/AbstractTestX509Parameterized.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.hadoop.hbase.io.crypto.tls;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseCommonTestingUtil;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.runners.Parameterized;
+
+/**
+ * Base class for parameterized unit tests that use X509TestContext for testing different X509
+ * parameter combinations (CA key type, cert key type, with/without a password, with/without
+ * hostname verification, etc).
+ *
+ * This base class takes care of setting up / cleaning up the test environment, and caching the
+ * X509TestContext objects used by the tests.
+ *
+ * This file has been copied from the Apache ZooKeeper project.
+ * @see Base
+ * revision
+ */
+public abstract class AbstractTestX509Parameterized {
+
+ private static final HBaseCommonTestingUtil UTIL = new HBaseCommonTestingUtil();
+ private static X509TestContextProvider PROVIDER;
+
+ @Parameterized.Parameter()
+ public X509KeyType caKeyType;
+
+ @Parameterized.Parameter(value = 1)
+ public X509KeyType certKeyType;
+
+ @Parameterized.Parameter(value = 2)
+ public char[] keyPassword;
+
+ @Parameterized.Parameter(value = 3)
+ public Integer paramIndex;
+
+ /**
+ * Default parameters suitable for most subclasses. See example usage in {@link TestX509Util}.
+ * @return an array of parameter combinations to test with.
+ */
+ @Parameterized.Parameters(
+ name = "{index}: caKeyType={0}, certKeyType={1}, keyPassword={2}, paramIndex={3}")
+ public static Collection defaultParams() {
+ List result = new ArrayList<>();
+ int paramIndex = 0;
+ for (X509KeyType caKeyType : X509KeyType.values()) {
+ for (X509KeyType certKeyType : X509KeyType.values()) {
+ for (char[] keyPassword : new char[][] { "".toCharArray(), "pa$$w0rd".toCharArray() }) {
+ result.add(new Object[] { caKeyType, certKeyType, keyPassword, paramIndex++ });
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Because key generation and writing / deleting files is kind of expensive, we cache the certs
+ * and on-disk files between test cases. None of the test cases modify any of this data so it's
+ * safe to reuse between tests. This caching makes all test cases after the first one for a given
+ * parameter combination complete almost instantly.
+ */
+ protected static Configuration conf;
+
+ protected X509TestContext x509TestContext;
+
+ @BeforeClass
+ public static void setUpBaseClass() throws Exception {
+ Security.addProvider(new BouncyCastleProvider());
+ File dir = new File(UTIL.getDataTestDir(TestX509Util.class.getSimpleName()).toString())
+ .getCanonicalFile();
+ FileUtils.forceMkdir(dir);
+ PROVIDER = new X509TestContextProvider(UTIL.getConfiguration(), dir);
+ }
+
+ @AfterClass
+ public static void cleanUpBaseClass() {
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+ UTIL.cleanupTestDir();
+ }
+
+ @Before
+ public void setUp() throws IOException {
+ x509TestContext = PROVIDER.get(caKeyType, certKeyType, keyPassword);
+ x509TestContext.setConfigurations(KeyStoreFileType.JKS, KeyStoreFileType.JKS);
+ conf = new Configuration(UTIL.getConfiguration());
+ }
+
+ @After
+ public void cleanUp() {
+ x509TestContext.clearConfigurations();
+ x509TestContext.getConf().unset(X509Util.TLS_CONFIG_OCSP);
+ x509TestContext.getConf().unset(X509Util.TLS_CONFIG_CLR);
+ x509TestContext.getConf().unset(X509Util.TLS_CONFIG_PROTOCOL);
+ System.clearProperty("com.sun.net.ssl.checkRevocation");
+ System.clearProperty("com.sun.security.enableCRLDP");
+ Security.setProperty("ocsp.enable", Boolean.FALSE.toString());
+ Security.setProperty("com.sun.security.enableCRLDP", Boolean.FALSE.toString());
+ }
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestBCFKSFileLoader.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestBCFKSFileLoader.java
new file mode 100644
index 000000000000..060c60a7a0ca
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestBCFKSFileLoader.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.hadoop.hbase.io.crypto.tls;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * This file has been copied from the Apache ZooKeeper project.
+ * @see Base
+ * revision
+ */
+@RunWith(Parameterized.class)
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestBCFKSFileLoader extends AbstractTestX509Parameterized {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestBCFKSFileLoader.class);
+
+ @Test
+ public void testLoadKeyStore() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.BCFKS).getAbsolutePath();
+ KeyStore ks = new BCFKSFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ Assert.assertEquals(1, ks.size());
+ }
+
+ @Test(expected = Exception.class)
+ public void testLoadKeyStoreWithWrongPassword() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.BCFKS).getAbsolutePath();
+ new BCFKSFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword("wrong password".toCharArray()).build().loadKeyStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadKeyStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.BCFKS).getAbsolutePath();
+ new BCFKSFileLoader.Builder().setKeyStorePath(path + ".does_not_exist")
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadKeyStoreWithNullFilePath() throws Exception {
+ new BCFKSFileLoader.Builder().setKeyStorePassword(x509TestContext.getKeyStorePassword()).build()
+ .loadKeyStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadKeyStoreWithWrongFileType() throws Exception {
+ // Trying to load a PEM file with BCFKS loader should fail
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new BCFKSFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test
+ public void testLoadTrustStore() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.BCFKS).getAbsolutePath();
+ KeyStore ts = new BCFKSFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ Assert.assertEquals(1, ts.size());
+ }
+
+ @Test(expected = Exception.class)
+ public void testLoadTrustStoreWithWrongPassword() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.BCFKS).getAbsolutePath();
+ new BCFKSFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword("wrong password".toCharArray()).build().loadTrustStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadTrustStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.BCFKS).getAbsolutePath();
+ new BCFKSFileLoader.Builder().setTrustStorePath(path + ".does_not_exist")
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadTrustStoreWithNullFilePath() throws Exception {
+ new BCFKSFileLoader.Builder().setTrustStorePassword(x509TestContext.getTrustStorePassword())
+ .build().loadTrustStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadTrustStoreWithWrongFileType() throws Exception {
+ // Trying to load a PEM file with BCFKS loader should fail
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new BCFKSFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ }
+
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestFileKeyStoreLoaderBuilderProvider.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestFileKeyStoreLoaderBuilderProvider.java
new file mode 100644
index 000000000000..a80103483345
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestFileKeyStoreLoaderBuilderProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.hadoop.hbase.io.crypto.tls;
+
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * This file has been copied from the Apache ZooKeeper project.
+ * @see Base
+ * revision
+ */
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestFileKeyStoreLoaderBuilderProvider {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestFileKeyStoreLoaderBuilderProvider.class);
+
+ @Test
+ public void testGetBuilderForJKSFileType() {
+ FileKeyStoreLoader.Builder> builder =
+ FileKeyStoreLoaderBuilderProvider.getBuilderForKeyStoreFileType(KeyStoreFileType.JKS);
+ Assert.assertTrue(builder instanceof JKSFileLoader.Builder);
+ }
+
+ @Test
+ public void testGetBuilderForPEMFileType() {
+ FileKeyStoreLoader.Builder> builder =
+ FileKeyStoreLoaderBuilderProvider.getBuilderForKeyStoreFileType(KeyStoreFileType.PEM);
+ Assert.assertTrue(builder instanceof PEMFileLoader.Builder);
+ }
+
+ @Test
+ public void testGetBuilderForPKCS12FileType() {
+ FileKeyStoreLoader.Builder> builder =
+ FileKeyStoreLoaderBuilderProvider.getBuilderForKeyStoreFileType(KeyStoreFileType.PKCS12);
+ Assert.assertTrue(builder instanceof PKCS12FileLoader.Builder);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetBuilderForNullFileType() {
+ FileKeyStoreLoaderBuilderProvider.getBuilderForKeyStoreFileType(null);
+ }
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestJKSFileLoader.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestJKSFileLoader.java
new file mode 100644
index 000000000000..6640e3b22f98
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestJKSFileLoader.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.hadoop.hbase.io.crypto.tls;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * This file has been copied from the Apache ZooKeeper project.
+ * @see Base
+ * revision
+ */
+@RunWith(Parameterized.class)
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestJKSFileLoader extends AbstractTestX509Parameterized {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestJKSFileLoader.class);
+
+ @Test
+ public void testLoadKeyStore() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ KeyStore ks = new JKSFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ Assert.assertEquals(1, ks.size());
+ }
+
+ @Test(expected = Exception.class)
+ public void testLoadKeyStoreWithWrongPassword() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ new JKSFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword("wrong password".toCharArray()).build().loadKeyStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadKeyStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ new JKSFileLoader.Builder().setKeyStorePath(path + ".does_not_exist")
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadKeyStoreWithNullFilePath() throws Exception {
+ new JKSFileLoader.Builder().setKeyStorePassword(x509TestContext.getKeyStorePassword()).build()
+ .loadKeyStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadKeyStoreWithWrongFileType() throws Exception {
+ // Trying to load a PEM file with JKS loader should fail
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new JKSFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test
+ public void testLoadTrustStore() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ KeyStore ts = new JKSFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ Assert.assertEquals(1, ts.size());
+ }
+
+ @Test(expected = Exception.class)
+ public void testLoadTrustStoreWithWrongPassword() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ new JKSFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword("wrong password".toCharArray()).build().loadTrustStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadTrustStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ new JKSFileLoader.Builder().setTrustStorePath(path + ".does_not_exist")
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadTrustStoreWithNullFilePath() throws Exception {
+ new JKSFileLoader.Builder().setTrustStorePassword(x509TestContext.getTrustStorePassword())
+ .build().loadTrustStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadTrustStoreWithWrongFileType() throws Exception {
+ // Trying to load a PEM file with JKS loader should fail
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new JKSFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ }
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestKeyStoreFileType.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestKeyStoreFileType.java
new file mode 100644
index 000000000000..d3f457fb4d33
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestKeyStoreFileType.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.hadoop.hbase.io.crypto.tls;
+
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+/**
+ * This file has been copied from the Apache ZooKeeper project.
+ * @see Base
+ * revision
+ */
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestKeyStoreFileType {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestKeyStoreFileType.class);
+
+ @Test
+ public void testGetPropertyValue() {
+ Assert.assertEquals("PEM", KeyStoreFileType.PEM.getPropertyValue());
+ Assert.assertEquals("JKS", KeyStoreFileType.JKS.getPropertyValue());
+ Assert.assertEquals("PKCS12", KeyStoreFileType.PKCS12.getPropertyValue());
+ Assert.assertEquals("BCFKS", KeyStoreFileType.BCFKS.getPropertyValue());
+ }
+
+ @Test
+ public void testFromPropertyValue() {
+ Assert.assertEquals(KeyStoreFileType.PEM, KeyStoreFileType.fromPropertyValue("PEM"));
+ Assert.assertEquals(KeyStoreFileType.JKS, KeyStoreFileType.fromPropertyValue("JKS"));
+ Assert.assertEquals(KeyStoreFileType.PKCS12, KeyStoreFileType.fromPropertyValue("PKCS12"));
+ Assert.assertEquals(KeyStoreFileType.BCFKS, KeyStoreFileType.fromPropertyValue("BCFKS"));
+ Assert.assertNull(KeyStoreFileType.fromPropertyValue(""));
+ Assert.assertNull(KeyStoreFileType.fromPropertyValue(null));
+ }
+
+ @Test
+ public void testFromPropertyValueIgnoresCase() {
+ Assert.assertEquals(KeyStoreFileType.PEM, KeyStoreFileType.fromPropertyValue("pem"));
+ Assert.assertEquals(KeyStoreFileType.JKS, KeyStoreFileType.fromPropertyValue("jks"));
+ Assert.assertEquals(KeyStoreFileType.PKCS12, KeyStoreFileType.fromPropertyValue("pkcs12"));
+ Assert.assertEquals(KeyStoreFileType.BCFKS, KeyStoreFileType.fromPropertyValue("bcfks"));
+ Assert.assertNull(KeyStoreFileType.fromPropertyValue(""));
+ Assert.assertNull(KeyStoreFileType.fromPropertyValue(null));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFromPropertyValueThrowsOnBadPropertyValue() {
+ KeyStoreFileType.fromPropertyValue("foobar");
+ }
+
+ @Test
+ public void testFromFilename() {
+ Assert.assertEquals(KeyStoreFileType.JKS, KeyStoreFileType.fromFilename("mykey.jks"));
+ Assert.assertEquals(KeyStoreFileType.JKS,
+ KeyStoreFileType.fromFilename("/path/to/key/dir/mykey.jks"));
+ Assert.assertEquals(KeyStoreFileType.PEM, KeyStoreFileType.fromFilename("mykey.pem"));
+ Assert.assertEquals(KeyStoreFileType.PEM,
+ KeyStoreFileType.fromFilename("/path/to/key/dir/mykey.pem"));
+ Assert.assertEquals(KeyStoreFileType.PKCS12, KeyStoreFileType.fromFilename("mykey.p12"));
+ Assert.assertEquals(KeyStoreFileType.PKCS12,
+ KeyStoreFileType.fromFilename("/path/to/key/dir/mykey.p12"));
+ Assert.assertEquals(KeyStoreFileType.BCFKS, KeyStoreFileType.fromFilename("mykey.bcfks"));
+ Assert.assertEquals(KeyStoreFileType.BCFKS,
+ KeyStoreFileType.fromFilename("/path/to/key/dir/mykey.bcfks"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFromFilenameThrowsOnBadFileExtension() {
+ KeyStoreFileType.fromFilename("prod.key");
+ }
+
+ @Test
+ public void testFromPropertyValueOrFileName() {
+ // Property value takes precedence if provided
+ Assert.assertEquals(KeyStoreFileType.JKS,
+ KeyStoreFileType.fromPropertyValueOrFileName("JKS", "prod.key"));
+ Assert.assertEquals(KeyStoreFileType.PEM,
+ KeyStoreFileType.fromPropertyValueOrFileName("PEM", "prod.key"));
+ Assert.assertEquals(KeyStoreFileType.PKCS12,
+ KeyStoreFileType.fromPropertyValueOrFileName("PKCS12", "prod.key"));
+ Assert.assertEquals(KeyStoreFileType.BCFKS,
+ KeyStoreFileType.fromPropertyValueOrFileName("BCFKS", "prod.key"));
+ // Falls back to filename detection if no property value
+ Assert.assertEquals(KeyStoreFileType.JKS,
+ KeyStoreFileType.fromPropertyValueOrFileName("", "prod.jks"));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFromPropertyValueOrFileNameThrowsOnBadPropertyValue() {
+ KeyStoreFileType.fromPropertyValueOrFileName("foobar", "prod.jks");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testFromPropertyValueOrFileNameThrowsOnBadFileExtension() {
+ KeyStoreFileType.fromPropertyValueOrFileName("", "prod.key");
+ }
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestPEMFileLoader.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestPEMFileLoader.java
new file mode 100644
index 000000000000..0c9924f09075
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestPEMFileLoader.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.hadoop.hbase.io.crypto.tls;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * This file has been copied from the Apache ZooKeeper project.
+ * @see Base
+ * revision
+ */
+@RunWith(Parameterized.class)
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestPEMFileLoader extends AbstractTestX509Parameterized {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestPEMFileLoader.class);
+
+ @Test
+ public void testLoadKeyStore() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ KeyStore ks = new PEMFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ Assert.assertEquals(1, ks.size());
+ }
+
+ @Test(expected = Exception.class)
+ public void testLoadKeyStoreWithWrongPassword() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new PEMFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword("wrong password".toCharArray()).build().loadKeyStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadKeyStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new PEMFileLoader.Builder().setKeyStorePath(path + ".does_not_exist")
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadKeyStoreWithNullFilePath() throws Exception {
+ new PEMFileLoader.Builder().setKeyStorePassword(x509TestContext.getKeyStorePassword()).build()
+ .loadKeyStore();
+ }
+
+ @Test(expected = KeyStoreException.class)
+ public void testLoadKeyStoreWithWrongFileType() throws Exception {
+ // Trying to load a JKS file with PEM loader should fail
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ new PEMFileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test
+ public void testLoadTrustStore() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ KeyStore ts = new PEMFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ Assert.assertEquals(1, ts.size());
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadTrustStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new PEMFileLoader.Builder().setTrustStorePath(path + ".does_not_exist")
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadTrustStoreWithNullFilePath() throws Exception {
+ new PEMFileLoader.Builder().setTrustStorePassword(x509TestContext.getTrustStorePassword())
+ .build().loadTrustStore();
+ }
+
+ @Test
+ public void testLoadTrustStoreWithWrongFileType() throws Exception {
+ // Trying to load a JKS file with PEM loader should fail
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath();
+ KeyStore ts = new PEMFileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ Assert.assertEquals(0, ts.size());
+ }
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestPKCS12FileLoader.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestPKCS12FileLoader.java
new file mode 100644
index 000000000000..a0ff83833e22
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestPKCS12FileLoader.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.hadoop.hbase.io.crypto.tls;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/**
+ * This file has been copied from the Apache ZooKeeper project.
+ * @see Base
+ * revision
+ */
+@RunWith(Parameterized.class)
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestPKCS12FileLoader extends AbstractTestX509Parameterized {
+
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestPKCS12FileLoader.class);
+
+ @Test
+ public void testLoadKeyStore() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath();
+ KeyStore ks = new PKCS12FileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ Assert.assertEquals(1, ks.size());
+ }
+
+ @Test(expected = Exception.class)
+ public void testLoadKeyStoreWithWrongPassword() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath();
+ new PKCS12FileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword("wrong password".toCharArray()).build().loadKeyStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadKeyStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath();
+ new PKCS12FileLoader.Builder().setKeyStorePath(path + ".does_not_exist")
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadKeyStoreWithNullFilePath() throws Exception {
+ new PKCS12FileLoader.Builder().setKeyStorePassword(x509TestContext.getKeyStorePassword())
+ .build().loadKeyStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadKeyStoreWithWrongFileType() throws Exception {
+ // Trying to load a PEM file with PKCS12 loader should fail
+ String path = x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new PKCS12FileLoader.Builder().setKeyStorePath(path)
+ .setKeyStorePassword(x509TestContext.getKeyStorePassword()).build().loadKeyStore();
+ }
+
+ @Test
+ public void testLoadTrustStore() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath();
+ KeyStore ts = new PKCS12FileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ Assert.assertEquals(1, ts.size());
+ }
+
+ @Test(expected = Exception.class)
+ public void testLoadTrustStoreWithWrongPassword() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath();
+ new PKCS12FileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword("wrong password".toCharArray()).build().loadTrustStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadTrustStoreWithWrongFilePath() throws Exception {
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath();
+ new PKCS12FileLoader.Builder().setTrustStorePath(path + ".does_not_exist")
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testLoadTrustStoreWithNullFilePath() throws Exception {
+ new PKCS12FileLoader.Builder().setTrustStorePassword(x509TestContext.getTrustStorePassword())
+ .build().loadTrustStore();
+ }
+
+ @Test(expected = IOException.class)
+ public void testLoadTrustStoreWithWrongFileType() throws Exception {
+ // Trying to load a PEM file with PKCS12 loader should fail
+ String path = x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath();
+ new PKCS12FileLoader.Builder().setTrustStorePath(path)
+ .setTrustStorePassword(x509TestContext.getTrustStorePassword()).build().loadTrustStore();
+ }
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestX509Util.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestX509Util.java
index bb70c02946fb..f98950381157 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestX509Util.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/TestX509Util.java
@@ -28,30 +28,17 @@
import static org.junit.Assume.assumeThat;
import static org.mockito.Mockito.mock;
-import java.io.File;
-import java.io.IOException;
import java.security.Security;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
-import java.util.List;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
-import org.apache.commons.io.FileUtils;
-import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.HBaseCommonTestingUtil;
import org.apache.hadoop.hbase.exceptions.KeyManagerException;
import org.apache.hadoop.hbase.exceptions.SSLContextException;
import org.apache.hadoop.hbase.exceptions.TrustManagerException;
-import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SecurityTests;
import org.apache.hadoop.hbase.testclassification.SmallTests;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -68,83 +55,15 @@
* revision
*/
@RunWith(Parameterized.class)
-@Category({ MiscTests.class, SmallTests.class })
-public class TestX509Util {
+@Category({ SecurityTests.class, SmallTests.class })
+public class TestX509Util extends AbstractTestX509Parameterized {
@ClassRule
public static final HBaseClassTestRule CLASS_RULE =
HBaseClassTestRule.forClass(TestX509Util.class);
- private static final HBaseCommonTestingUtil UTIL = new HBaseCommonTestingUtil();
private static final char[] EMPTY_CHAR_ARRAY = new char[0];
- private static X509TestContextProvider PROVIDER;
-
- @Parameterized.Parameter()
- public X509KeyType caKeyType;
-
- @Parameterized.Parameter(value = 1)
- public X509KeyType certKeyType;
-
- @Parameterized.Parameter(value = 2)
- public char[] keyPassword;
-
- @Parameterized.Parameter(value = 3)
- public Integer paramIndex;
-
- private X509TestContext x509TestContext;
-
- private Configuration conf;
-
- @Parameterized.Parameters(
- name = "{index}: caKeyType={0}, certKeyType={1}, keyPassword={2}, paramIndex={3}")
- public static Collection data() {
- List params = new ArrayList<>();
- int paramIndex = 0;
- for (X509KeyType caKeyType : X509KeyType.values()) {
- for (X509KeyType certKeyType : X509KeyType.values()) {
- for (char[] keyPassword : new char[][] { "".toCharArray(), "pa$$w0rd".toCharArray() }) {
- params.add(new Object[] { caKeyType, certKeyType, keyPassword, paramIndex++ });
- }
- }
- }
- return params;
- }
-
- @BeforeClass
- public static void setUpBeforeClass() throws IOException {
- Security.addProvider(new BouncyCastleProvider());
- File dir = new File(UTIL.getDataTestDir(TestX509Util.class.getSimpleName()).toString())
- .getCanonicalFile();
- FileUtils.forceMkdir(dir);
- PROVIDER = new X509TestContextProvider(UTIL.getConfiguration(), dir);
- }
-
- @AfterClass
- public static void tearDownAfterClass() {
- Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
- UTIL.cleanupTestDir();
- }
-
- @Before
- public void setUp() throws IOException {
- x509TestContext = PROVIDER.get(caKeyType, certKeyType, keyPassword);
- x509TestContext.setConfigurations(KeyStoreFileType.JKS, KeyStoreFileType.JKS);
- conf = new Configuration(UTIL.getConfiguration());
- }
-
- @After
- public void cleanUp() {
- x509TestContext.clearConfigurations();
- x509TestContext.getConf().unset(X509Util.TLS_CONFIG_OCSP);
- x509TestContext.getConf().unset(X509Util.TLS_CONFIG_CLR);
- x509TestContext.getConf().unset(X509Util.TLS_CONFIG_PROTOCOL);
- System.clearProperty("com.sun.net.ssl.checkRevocation");
- System.clearProperty("com.sun.security.enableCRLDP");
- Security.setProperty("ocsp.enable", Boolean.FALSE.toString());
- Security.setProperty("com.sun.security.enableCRLDP", Boolean.FALSE.toString());
- }
-
@Test
public void testCreateSSLContextWithoutCustomProtocol() throws Exception {
SslContext sslContext = X509Util.createSslContextForClient(conf);
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContext.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContext.java
index b20850788603..27cb5bde3aca 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContext.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContext.java
@@ -31,7 +31,6 @@
import java.util.Arrays;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.yetus.audience.InterfaceAudience;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
@@ -60,6 +59,7 @@ public final class X509TestContext {
private File trustStoreJksFile;
private File trustStorePemFile;
private File trustStorePkcs12File;
+ private File trustStoreBcfksFile;
private final KeyPair keyStoreKeyPair;
private final X509Certificate keyStoreCertificate;
@@ -67,6 +67,7 @@ public final class X509TestContext {
private File keyStoreJksFile;
private File keyStorePemFile;
private File keyStorePkcs12File;
+ private File keyStoreBcfksFile;
/**
* Constructor is intentionally private, use the Builder class instead.
@@ -137,6 +138,8 @@ public File getTrustStoreFile(KeyStoreFileType storeFileType) throws IOException
return getTrustStorePemFile();
case PKCS12:
return getTrustStorePkcs12File();
+ case BCFKS:
+ return getTrustStoreBcfksFile();
default:
throw new IllegalArgumentException("Invalid trust store type: " + storeFileType
+ ", must be one of: " + Arrays.toString(KeyStoreFileType.values()));
@@ -194,6 +197,25 @@ private File getTrustStorePkcs12File() throws IOException {
return trustStorePkcs12File;
}
+ private File getTrustStoreBcfksFile() throws IOException {
+ if (trustStoreBcfksFile == null) {
+ File trustStoreBcfksFile = File.createTempFile(TRUST_STORE_PREFIX,
+ KeyStoreFileType.BCFKS.getDefaultFileExtension(), tempDir);
+ trustStoreBcfksFile.deleteOnExit();
+ try (
+ final FileOutputStream trustStoreOutputStream = new FileOutputStream(trustStoreBcfksFile)) {
+ byte[] bytes =
+ X509TestHelpers.certToBCFKSTrustStoreBytes(trustStoreCertificate, trustStorePassword);
+ trustStoreOutputStream.write(bytes);
+ trustStoreOutputStream.flush();
+ } catch (GeneralSecurityException e) {
+ throw new IOException(e);
+ }
+ this.trustStoreBcfksFile = trustStoreBcfksFile;
+ }
+ return trustStoreBcfksFile;
+ }
+
public X509Certificate getKeyStoreCertificate() {
return keyStoreCertificate;
}
@@ -226,6 +248,8 @@ public File getKeyStoreFile(KeyStoreFileType storeFileType) throws IOException {
return getKeyStorePemFile();
case PKCS12:
return getKeyStorePkcs12File();
+ case BCFKS:
+ return getKeyStoreBcfksFile();
default:
throw new IllegalArgumentException("Invalid key store type: " + storeFileType
+ ", must be one of: " + Arrays.toString(KeyStoreFileType.values()));
@@ -286,6 +310,24 @@ private File getKeyStorePkcs12File() throws IOException {
return keyStorePkcs12File;
}
+ private File getKeyStoreBcfksFile() throws IOException {
+ if (keyStoreBcfksFile == null) {
+ File keyStoreBcfksFile = File.createTempFile(KEY_STORE_PREFIX,
+ KeyStoreFileType.BCFKS.getDefaultFileExtension(), tempDir);
+ keyStoreBcfksFile.deleteOnExit();
+ try (final FileOutputStream keyStoreOutputStream = new FileOutputStream(keyStoreBcfksFile)) {
+ byte[] bytes = X509TestHelpers.certAndPrivateKeyToBCFKSBytes(keyStoreCertificate,
+ keyStoreKeyPair.getPrivate(), keyStorePassword);
+ keyStoreOutputStream.write(bytes);
+ keyStoreOutputStream.flush();
+ } catch (GeneralSecurityException e) {
+ throw new IOException(e);
+ }
+ this.keyStoreBcfksFile = keyStoreBcfksFile;
+ }
+ return keyStoreBcfksFile;
+ }
+
/**
* Sets the SSL system properties such that the given X509Util object can be used to create SSL
* Contexts that will use the trust store and key store files created by this test context.
@@ -413,14 +455,6 @@ public Builder setKeyStorePassword(char[] password) {
}
}
- /**
- * Returns a new default-constructed Builder.
- * @return a new Builder.
- */
- public static Builder newBuilder() {
- return newBuilder(HBaseConfiguration.create());
- }
-
/**
* Returns a new default-constructed Builder.
* @return a new Builder.
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContextProvider.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContextProvider.java
index 3024755a2e3e..d65cdbe689dd 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContextProvider.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestContextProvider.java
@@ -18,7 +18,10 @@
package org.apache.hadoop.hbase.io.crypto.tls;
import java.io.File;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
import java.util.Objects;
import org.apache.hadoop.conf.Configuration;
@@ -83,4 +86,18 @@ public X509TestContextProvider(Configuration conf, File tempDir) {
public X509TestContext get(X509KeyType caKeyType, X509KeyType certKeyType, char[] keyPassword) {
return ctxs.getUnchecked(new CacheKey(caKeyType, certKeyType, keyPassword));
}
+
+ static Collection defaultParams() {
+ List params = new ArrayList<>();
+ int paramIndex = 0;
+ for (X509KeyType caKeyType : X509KeyType.values()) {
+ for (X509KeyType certKeyType : X509KeyType.values()) {
+ for (char[] keyPassword : new char[][] { "".toCharArray(), "pa$$w0rd".toCharArray() }) {
+ params.add(new Object[] { caKeyType, certKeyType, keyPassword, paramIndex++ });
+ }
+ }
+ }
+ return params;
+ }
+
}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestHelpers.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestHelpers.java
index 42c798abcd9e..968e616ef569 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestHelpers.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/io/crypto/tls/X509TestHelpers.java
@@ -341,6 +341,23 @@ public static byte[] certToPKCS12TrustStoreBytes(X509Certificate cert, char[] ke
return certToTrustStoreBytes(cert, keyPassword, trustStore);
}
+ /**
+ * Encodes the given X509Certificate as a BCFKS TrustStore, optionally protecting the cert with a
+ * password (though it's unclear why one would do this since certificates only contain public
+ * information and do not need to be kept secret). Returns the byte array encoding of the trust
+ * store, which may be written to a file and loaded to instantiate the trust store at a later
+ * point or in another process.
+ * @param cert the certificate to serialize.
+ * @param keyPassword an optional password to encrypt the trust store. If empty or null, the cert
+ * will not be encrypted.
+ * @return the serialized bytes of the BCFKS trust store. nn
+ */
+ public static byte[] certToBCFKSTrustStoreBytes(X509Certificate cert, char[] keyPassword)
+ throws IOException, GeneralSecurityException {
+ KeyStore trustStore = KeyStore.getInstance("BCFKS");
+ return certToTrustStoreBytes(cert, keyPassword, trustStore);
+ }
+
private static byte[] certToTrustStoreBytes(X509Certificate cert, char[] keyPassword,
KeyStore trustStore) throws IOException, GeneralSecurityException {
trustStore.load(null, keyPassword);
@@ -387,6 +404,23 @@ public static byte[] certAndPrivateKeyToPKCS12Bytes(X509Certificate cert, Privat
return certAndPrivateKeyToBytes(cert, privateKey, keyPassword, keyStore);
}
+ /**
+ * Encodes the given X509Certificate and private key as a BCFKS KeyStore, optionally protecting
+ * the private key (and possibly the cert?) with a password. Returns the byte array encoding of
+ * the key store, which may be written to a file and loaded to instantiate the key store at a
+ * later point or in another process.
+ * @param cert the X509 certificate to serialize.
+ * @param privateKey the private key to serialize.
+ * @param keyPassword an optional key password. If empty or null, the private key will not be
+ * encrypted.
+ * @return the serialized bytes of the BCFKS key store. nn
+ */
+ public static byte[] certAndPrivateKeyToBCFKSBytes(X509Certificate cert, PrivateKey privateKey,
+ char[] keyPassword) throws IOException, GeneralSecurityException {
+ KeyStore keyStore = KeyStore.getInstance("BCFKS");
+ return certAndPrivateKeyToBytes(cert, privateKey, keyPassword, keyStore);
+ }
+
private static byte[] certAndPrivateKeyToBytes(X509Certificate cert, PrivateKey privateKey,
char[] keyPassword, KeyStore keyStore) throws IOException, GeneralSecurityException {
keyStore.load(null, keyPassword);