HBASE-27346 Autodetect key/truststore file type from file extension (#4757)
Signed-off-by: Duo Zhang <zhangduo@apache.org> Signed-off-by: Bryan Beaudreault <bbeaudreault@apache.org>
This commit is contained in:
parent
ee58f177f0
commit
d2cc840edf
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Implementation of {@link FileKeyStoreLoader} that loads from BCKFS files.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/BCFKSFileLoader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
final class BCFKSFileLoader extends StandardTypeFileKeyStoreLoader {
|
||||
private BCFKSFileLoader(String keyStorePath, String trustStorePath, char[] keyStorePassword,
|
||||
char[] trustStorePassword) {
|
||||
super(keyStorePath, trustStorePath, keyStorePassword, trustStorePassword,
|
||||
SupportedStandardKeyFormat.BCFKS);
|
||||
}
|
||||
|
||||
static class Builder extends FileKeyStoreLoader.Builder<BCFKSFileLoader> {
|
||||
@Override
|
||||
BCFKSFileLoader build() {
|
||||
return new BCFKSFileLoader(keyStorePath, trustStorePath, keyStorePassword,
|
||||
trustStorePassword);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.util.Objects;
|
||||
|
||||
/**
|
||||
* Base class for instances of {@link KeyStoreLoader} which load the key/trust stores from files on
|
||||
* a filesystem.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/FileKeyStoreLoader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
abstract class FileKeyStoreLoader implements KeyStoreLoader {
|
||||
final String keyStorePath;
|
||||
final String trustStorePath;
|
||||
final char[] keyStorePassword;
|
||||
final char[] trustStorePassword;
|
||||
|
||||
FileKeyStoreLoader(String keyStorePath, String trustStorePath, char[] keyStorePassword,
|
||||
char[] trustStorePassword) {
|
||||
this.keyStorePath = keyStorePath;
|
||||
this.trustStorePath = trustStorePath;
|
||||
this.keyStorePassword = keyStorePassword;
|
||||
this.trustStorePassword = trustStorePassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for builder pattern used by subclasses.
|
||||
* @param <T> the subtype of FileKeyStoreLoader created by the Builder.
|
||||
*/
|
||||
static abstract class Builder<T extends FileKeyStoreLoader> {
|
||||
String keyStorePath;
|
||||
String trustStorePath;
|
||||
char[] keyStorePassword;
|
||||
char[] trustStorePassword;
|
||||
|
||||
Builder() {
|
||||
}
|
||||
|
||||
Builder<T> setKeyStorePath(String keyStorePath) {
|
||||
this.keyStorePath = Objects.requireNonNull(keyStorePath);
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setTrustStorePath(String trustStorePath) {
|
||||
this.trustStorePath = Objects.requireNonNull(trustStorePath);
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setKeyStorePassword(char[] keyStorePassword) {
|
||||
this.keyStorePassword = Objects.requireNonNull(keyStorePassword);
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder<T> setTrustStorePassword(char[] trustStorePassword) {
|
||||
this.trustStorePassword = Objects.requireNonNull(trustStorePassword);
|
||||
return this;
|
||||
}
|
||||
|
||||
abstract T build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.util.Objects;
|
||||
|
||||
/**
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/FileKeyStoreLoaderBuilderProvider.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
final class FileKeyStoreLoaderBuilderProvider {
|
||||
/**
|
||||
* Returns a {@link FileKeyStoreLoader.Builder} that can build a loader which loads keys and certs
|
||||
* from files of the given {@link KeyStoreFileType}.
|
||||
* @param type the file type to load keys/certs from.
|
||||
* @return a new Builder.
|
||||
*/
|
||||
static FileKeyStoreLoader.Builder<? extends FileKeyStoreLoader>
|
||||
getBuilderForKeyStoreFileType(KeyStoreFileType type) {
|
||||
switch (Objects.requireNonNull(type)) {
|
||||
case JKS:
|
||||
return new JKSFileLoader.Builder();
|
||||
case PEM:
|
||||
return new PEMFileLoader.Builder();
|
||||
case PKCS12:
|
||||
return new PKCS12FileLoader.Builder();
|
||||
case BCFKS:
|
||||
return new BCFKSFileLoader.Builder();
|
||||
default:
|
||||
throw new AssertionError("Unexpected StoreFileType: " + type.name());
|
||||
}
|
||||
}
|
||||
|
||||
private FileKeyStoreLoaderBuilderProvider() {
|
||||
// disabled
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Implementation of {@link FileKeyStoreLoader} that loads from JKS files.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/JKSFileLoader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
final class JKSFileLoader extends StandardTypeFileKeyStoreLoader {
|
||||
private JKSFileLoader(String keyStorePath, String trustStorePath, char[] keyStorePassword,
|
||||
char[] trustStorePassword) {
|
||||
super(keyStorePath, trustStorePath, keyStorePassword, trustStorePassword,
|
||||
SupportedStandardKeyFormat.JKS);
|
||||
}
|
||||
|
||||
static class Builder extends FileKeyStoreLoader.Builder<JKSFileLoader> {
|
||||
@Override
|
||||
JKSFileLoader build() {
|
||||
return new JKSFileLoader(keyStorePath, trustStorePath, keyStorePassword, trustStorePassword);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
|
||||
/**
|
||||
* An interface for an object that can load key stores or trust stores.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/KeyStoreLoader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
interface KeyStoreLoader {
|
||||
/**
|
||||
* Loads a KeyStore which contains at least one private key and the associated X509 cert chain.
|
||||
* @return a new KeyStore
|
||||
* @throws IOException if loading the key store fails due to an IO error, such as
|
||||
* "file not found".
|
||||
* @throws GeneralSecurityException if loading the key store fails due to a security error, such
|
||||
* as "unsupported crypto algorithm".
|
||||
*/
|
||||
KeyStore loadKeyStore() throws IOException, GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* Loads a KeyStore which contains at least one X509 cert chain for a trusted Certificate
|
||||
* Authority (CA).
|
||||
* @return a new KeyStore
|
||||
* @throws IOException if loading the trust store fails due to an IO error, such as
|
||||
* "file not found".
|
||||
* @throws GeneralSecurityException if loading the trust store fails due to a security error, such
|
||||
* as "unsupported crypto algorithm".
|
||||
*/
|
||||
KeyStore loadTrustStore() throws IOException, GeneralSecurityException;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
|
||||
/**
|
||||
* Implementation of {@link FileKeyStoreLoader} that loads from PEM files.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/PEMFileLoader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
final class PEMFileLoader extends FileKeyStoreLoader {
|
||||
private PEMFileLoader(String keyStorePath, String trustStorePath, char[] keyStorePassword,
|
||||
char[] trustStorePassword) {
|
||||
super(keyStorePath, trustStorePath, keyStorePassword, trustStorePassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore loadKeyStore() throws IOException, GeneralSecurityException {
|
||||
File file = new File(keyStorePath);
|
||||
return PemReader.loadKeyStore(file, file, keyStorePassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore loadTrustStore() throws IOException, GeneralSecurityException {
|
||||
return PemReader.loadTrustStore(new File(trustStorePath));
|
||||
}
|
||||
|
||||
static class Builder extends FileKeyStoreLoader.Builder<PEMFileLoader> {
|
||||
@Override
|
||||
PEMFileLoader build() {
|
||||
return new PEMFileLoader(keyStorePath, trustStorePath, keyStorePassword, trustStorePassword);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Implementation of {@link FileKeyStoreLoader} that loads from PKCS12 files.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/PKCS12FileLoader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
final class PKCS12FileLoader extends StandardTypeFileKeyStoreLoader {
|
||||
private PKCS12FileLoader(String keyStorePath, String trustStorePath, char[] keyStorePassword,
|
||||
char[] trustStorePassword) {
|
||||
super(keyStorePath, trustStorePath, keyStorePassword, trustStorePassword,
|
||||
SupportedStandardKeyFormat.PKCS12);
|
||||
}
|
||||
|
||||
static class Builder extends FileKeyStoreLoader.Builder<PKCS12FileLoader> {
|
||||
@Override
|
||||
PKCS12FileLoader build() {
|
||||
return new PKCS12FileLoader(keyStorePath, trustStorePath, keyStorePassword,
|
||||
trustStorePassword);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* 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 static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static java.util.Base64.getMimeDecoder;
|
||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||
import static javax.crypto.Cipher.DECRYPT_MODE;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.EncryptedPrivateKeyInfo;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
/**
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/util/PemReader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
final class PemReader {
|
||||
private static final Pattern CERT_PATTERN =
|
||||
Pattern.compile("-+BEGIN\\s+.*CERTIFICATE[^-]*-+(?:\\s|\\r|\\n)+" + // Header
|
||||
"([a-z0-9+/=\\r\\n]+)" + // Base64 text
|
||||
"-+END\\s+.*CERTIFICATE[^-]*-+", // Footer
|
||||
CASE_INSENSITIVE);
|
||||
|
||||
private static final Pattern PRIVATE_KEY_PATTERN =
|
||||
Pattern.compile("-+BEGIN\\s+.*PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n)+" + // Header
|
||||
"([a-z0-9+/=\\r\\n]+)" + // Base64 text
|
||||
"-+END\\s+.*PRIVATE\\s+KEY[^-]*-+", // Footer
|
||||
CASE_INSENSITIVE);
|
||||
|
||||
private static final Pattern PUBLIC_KEY_PATTERN =
|
||||
Pattern.compile("-+BEGIN\\s+.*PUBLIC\\s+KEY[^-]*-+(?:\\s|\\r|\\n)+" + // Header
|
||||
"([a-z0-9+/=\\r\\n]+)" + // Base64 text
|
||||
"-+END\\s+.*PUBLIC\\s+KEY[^-]*-+", // Footer
|
||||
CASE_INSENSITIVE);
|
||||
|
||||
private PemReader() {
|
||||
}
|
||||
|
||||
public static KeyStore loadTrustStore(File certificateChainFile)
|
||||
throws IOException, GeneralSecurityException {
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
keyStore.load(null, null);
|
||||
|
||||
List<X509Certificate> certificateChain = readCertificateChain(certificateChainFile);
|
||||
for (X509Certificate certificate : certificateChain) {
|
||||
X500Principal principal = certificate.getSubjectX500Principal();
|
||||
keyStore.setCertificateEntry(principal.getName("RFC2253"), certificate);
|
||||
}
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
public static KeyStore loadKeyStore(File certificateChainFile, File privateKeyFile,
|
||||
char[] keyPassword) throws IOException, GeneralSecurityException {
|
||||
PrivateKey key = loadPrivateKey(privateKeyFile, keyPassword);
|
||||
|
||||
List<X509Certificate> certificateChain = readCertificateChain(certificateChainFile);
|
||||
if (certificateChain.isEmpty()) {
|
||||
throw new CertificateException(
|
||||
"Certificate file does not contain any certificates: " + certificateChainFile);
|
||||
}
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
keyStore.load(null, null);
|
||||
keyStore.setKeyEntry("key", key, keyPassword, certificateChain.toArray(new Certificate[0]));
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
public static List<X509Certificate> readCertificateChain(File certificateChainFile)
|
||||
throws IOException, GeneralSecurityException {
|
||||
String contents = new String(Files.readAllBytes(certificateChainFile.toPath()), US_ASCII);
|
||||
return readCertificateChain(contents);
|
||||
}
|
||||
|
||||
public static List<X509Certificate> readCertificateChain(String certificateChain)
|
||||
throws CertificateException {
|
||||
Matcher matcher = CERT_PATTERN.matcher(certificateChain);
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||
List<X509Certificate> certificates = new ArrayList<>();
|
||||
|
||||
int start = 0;
|
||||
while (matcher.find(start)) {
|
||||
byte[] buffer = base64Decode(matcher.group(1));
|
||||
certificates.add(
|
||||
(X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(buffer)));
|
||||
start = matcher.end();
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
public static PrivateKey loadPrivateKey(File privateKeyFile, char[] keyPassword)
|
||||
throws IOException, GeneralSecurityException {
|
||||
String privateKey = new String(Files.readAllBytes(privateKeyFile.toPath()), US_ASCII);
|
||||
return loadPrivateKey(privateKey, keyPassword);
|
||||
}
|
||||
|
||||
public static PrivateKey loadPrivateKey(String privateKey, char[] keyPassword)
|
||||
throws IOException, GeneralSecurityException {
|
||||
Matcher matcher = PRIVATE_KEY_PATTERN.matcher(privateKey);
|
||||
if (!matcher.find()) {
|
||||
throw new KeyStoreException("did not find a private key");
|
||||
}
|
||||
byte[] encodedKey = base64Decode(matcher.group(1));
|
||||
|
||||
PKCS8EncodedKeySpec encodedKeySpec;
|
||||
if (keyPassword != null && keyPassword.length > 0) {
|
||||
EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(encodedKey);
|
||||
SecretKeyFactory keyFactory =
|
||||
SecretKeyFactory.getInstance(encryptedPrivateKeyInfo.getAlgName());
|
||||
SecretKey secretKey = keyFactory.generateSecret(new PBEKeySpec(keyPassword));
|
||||
|
||||
Cipher cipher = Cipher.getInstance(encryptedPrivateKeyInfo.getAlgName());
|
||||
cipher.init(DECRYPT_MODE, secretKey, encryptedPrivateKeyInfo.getAlgParameters());
|
||||
|
||||
encodedKeySpec = encryptedPrivateKeyInfo.getKeySpec(cipher);
|
||||
} else {
|
||||
encodedKeySpec = new PKCS8EncodedKeySpec(encodedKey);
|
||||
}
|
||||
|
||||
// this code requires a key in PKCS8 format which is not the default openssl format
|
||||
// to convert to the PKCS8 format you use : openssl pkcs8 -topk8 ...
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
return keyFactory.generatePrivate(encodedKeySpec);
|
||||
} catch (InvalidKeySpecException ignore) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("EC");
|
||||
return keyFactory.generatePrivate(encodedKeySpec);
|
||||
} catch (InvalidKeySpecException ignore) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
||||
return keyFactory.generatePrivate(encodedKeySpec);
|
||||
}
|
||||
|
||||
public static PublicKey loadPublicKey(File publicKeyFile)
|
||||
throws IOException, GeneralSecurityException {
|
||||
String publicKey = new String(Files.readAllBytes(publicKeyFile.toPath()), US_ASCII);
|
||||
return loadPublicKey(publicKey);
|
||||
}
|
||||
|
||||
public static PublicKey loadPublicKey(String publicKey) throws GeneralSecurityException {
|
||||
Matcher matcher = PUBLIC_KEY_PATTERN.matcher(publicKey);
|
||||
if (!matcher.find()) {
|
||||
throw new KeyStoreException("did not find a public key");
|
||||
}
|
||||
String data = matcher.group(1);
|
||||
byte[] encodedKey = base64Decode(data);
|
||||
|
||||
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(encodedKey);
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
return keyFactory.generatePublic(encodedKeySpec);
|
||||
} catch (InvalidKeySpecException ignore) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("EC");
|
||||
return keyFactory.generatePublic(encodedKeySpec);
|
||||
} catch (InvalidKeySpecException ignore) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
|
||||
return keyFactory.generatePublic(encodedKeySpec);
|
||||
}
|
||||
|
||||
private static byte[] base64Decode(String base64) {
|
||||
return getMimeDecoder().decode(base64.getBytes(US_ASCII));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
|
||||
/**
|
||||
* Base class for instances of {@link KeyStoreLoader} which load the key/trust stores from files on
|
||||
* a filesystem using standard {@link KeyStore} types like JKS or PKCS12.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/c74658d398cdc1d207aa296cb6e20de00faec03e/zookeeper-server/src/main/java/org/apache/zookeeper/common/StandardTypeFileKeyStoreLoader.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
abstract class StandardTypeFileKeyStoreLoader extends FileKeyStoreLoader {
|
||||
private static final char[] EMPTY_CHAR_ARRAY = new char[0];
|
||||
|
||||
protected final SupportedStandardKeyFormat format;
|
||||
|
||||
protected enum SupportedStandardKeyFormat {
|
||||
JKS,
|
||||
PKCS12,
|
||||
BCFKS
|
||||
}
|
||||
|
||||
StandardTypeFileKeyStoreLoader(String keyStorePath, String trustStorePath,
|
||||
char[] keyStorePassword, char[] trustStorePassword, SupportedStandardKeyFormat format) {
|
||||
super(keyStorePath, trustStorePath, keyStorePassword, trustStorePassword);
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore loadKeyStore() throws IOException, GeneralSecurityException {
|
||||
try (InputStream inputStream = Files.newInputStream(new File(keyStorePath).toPath())) {
|
||||
KeyStore ks = keyStoreInstance();
|
||||
ks.load(inputStream, passwordStringToCharArray(keyStorePassword));
|
||||
return ks;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore loadTrustStore() throws IOException, GeneralSecurityException {
|
||||
try (InputStream inputStream = Files.newInputStream(new File(trustStorePath).toPath())) {
|
||||
KeyStore ts = keyStoreInstance();
|
||||
ts.load(inputStream, passwordStringToCharArray(trustStorePassword));
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
private KeyStore keyStoreInstance() throws KeyStoreException {
|
||||
return KeyStore.getInstance(format.name());
|
||||
}
|
||||
|
||||
private static char[] passwordStringToCharArray(char[] password) {
|
||||
return password == null ? EMPTY_CHAR_ARRAY : password;
|
||||
}
|
||||
}
|
|
@ -17,10 +17,7 @@
|
|||
*/
|
||||
package org.apache.hadoop.hbase.io.crypto.tls;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Security;
|
||||
|
@ -227,19 +224,16 @@ public final class X509Util {
|
|||
static X509KeyManager createKeyManager(String keyStoreLocation, char[] keyStorePassword,
|
||||
String keyStoreType) throws KeyManagerException {
|
||||
|
||||
if (keyStoreType == null) {
|
||||
keyStoreType = "jks";
|
||||
}
|
||||
|
||||
if (keyStorePassword == null) {
|
||||
keyStorePassword = EMPTY_CHAR_ARRAY;
|
||||
}
|
||||
|
||||
try {
|
||||
KeyStore ks = KeyStore.getInstance(keyStoreType);
|
||||
try (InputStream inputStream = Files.newInputStream(new File(keyStoreLocation).toPath())) {
|
||||
ks.load(inputStream, keyStorePassword);
|
||||
}
|
||||
KeyStoreFileType storeFileType =
|
||||
KeyStoreFileType.fromPropertyValueOrFileName(keyStoreType, keyStoreLocation);
|
||||
KeyStore ks = FileKeyStoreLoaderBuilderProvider.getBuilderForKeyStoreFileType(storeFileType)
|
||||
.setKeyStorePath(keyStoreLocation).setKeyStorePassword(keyStorePassword).build()
|
||||
.loadKeyStore();
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
|
||||
kmf.init(ks, keyStorePassword);
|
||||
|
@ -272,19 +266,16 @@ public final class X509Util {
|
|||
static X509TrustManager createTrustManager(String trustStoreLocation, char[] trustStorePassword,
|
||||
String trustStoreType, boolean crlEnabled, boolean ocspEnabled) throws TrustManagerException {
|
||||
|
||||
if (trustStoreType == null) {
|
||||
trustStoreType = "jks";
|
||||
}
|
||||
|
||||
if (trustStorePassword == null) {
|
||||
trustStorePassword = EMPTY_CHAR_ARRAY;
|
||||
}
|
||||
|
||||
try {
|
||||
KeyStore ts = KeyStore.getInstance(trustStoreType);
|
||||
try (InputStream inputStream = Files.newInputStream(new File(trustStoreLocation).toPath())) {
|
||||
ts.load(inputStream, trustStorePassword);
|
||||
}
|
||||
KeyStoreFileType storeFileType =
|
||||
KeyStoreFileType.fromPropertyValueOrFileName(trustStoreType, trustStoreLocation);
|
||||
KeyStore ts = FileKeyStoreLoaderBuilderProvider.getBuilderForKeyStoreFileType(storeFileType)
|
||||
.setTrustStorePath(trustStoreLocation).setTrustStorePassword(trustStorePassword).build()
|
||||
.loadTrustStore();
|
||||
|
||||
PKIXBuilderParameters pbParams = new PKIXBuilderParameters(ts, new X509CertSelector());
|
||||
if (crlEnabled || ocspEnabled) {
|
||||
|
|
|
@ -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).
|
||||
* <p/>
|
||||
* This base class takes care of setting up / cleaning up the test environment, and caching the
|
||||
* X509TestContext objects used by the tests.
|
||||
* <p/>
|
||||
* This file has been copied from the Apache ZooKeeper project.
|
||||
* @see <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/BaseX509ParameterizedTestCase.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
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<Object[]> defaultParams() {
|
||||
List<Object[]> 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());
|
||||
}
|
||||
}
|
|
@ -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 <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/BCFKSFileLoaderTest.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/FileKeyStoreLoaderBuilderProviderTest.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
}
|
|
@ -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 <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/JKSFileLoaderTest.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
}
|
|
@ -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 <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/KeyStoreFileTypeTest.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
@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");
|
||||
}
|
||||
}
|
|
@ -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 <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/PEMFileLoaderTest.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
@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());
|
||||
}
|
||||
}
|
|
@ -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 <a href=
|
||||
* "https://github.com/apache/zookeeper/blob/master/zookeeper-server/src/test/java/org/apache/zookeeper/common/PKCS12FileLoaderTest.java">Base
|
||||
* revision</a>
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
}
|
|
@ -28,28 +28,15 @@ import static org.junit.Assert.assertTrue;
|
|||
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 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;
|
||||
|
@ -66,83 +53,15 @@ import org.apache.hbase.thirdparty.io.netty.handler.ssl.SslContext;
|
|||
* revision</a>
|
||||
*/
|
||||
@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<Object[]> data() {
|
||||
List<Object[]> 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);
|
||||
|
@ -204,6 +123,69 @@ public class TestX509Util {
|
|||
assertFalse(Boolean.valueOf(Security.getProperty("ocsp.enable")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPEMKeyStore() throws Exception {
|
||||
// Make sure we can instantiate a key manager from the PEM file on disk
|
||||
X509Util.createKeyManager(
|
||||
x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath(),
|
||||
x509TestContext.getKeyStorePassword(), KeyStoreFileType.PEM.getPropertyValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPEMKeyStoreNullPassword() throws Exception {
|
||||
assumeThat(x509TestContext.getKeyStorePassword(), equalTo(EMPTY_CHAR_ARRAY));
|
||||
// Make sure that empty password and null password are treated the same
|
||||
X509Util.createKeyManager(
|
||||
x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath(), null,
|
||||
KeyStoreFileType.PEM.getPropertyValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPEMKeyStoreAutodetectStoreFileType() throws Exception {
|
||||
// Make sure we can instantiate a key manager from the PEM file on disk
|
||||
X509Util.createKeyManager(
|
||||
x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath(),
|
||||
x509TestContext.getKeyStorePassword(),
|
||||
null /* null StoreFileType means 'autodetect from file extension' */);
|
||||
}
|
||||
|
||||
@Test(expected = KeyManagerException.class)
|
||||
public void testLoadPEMKeyStoreWithWrongPassword() throws Exception {
|
||||
// Attempting to load with the wrong key password should fail
|
||||
X509Util.createKeyManager(
|
||||
x509TestContext.getKeyStoreFile(KeyStoreFileType.PEM).getAbsolutePath(),
|
||||
"wrong password".toCharArray(), // intentionally use the wrong password
|
||||
KeyStoreFileType.PEM.getPropertyValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPEMTrustStore() throws Exception {
|
||||
// Make sure we can instantiate a trust manager from the PEM file on disk
|
||||
X509Util.createTrustManager(
|
||||
x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath(),
|
||||
x509TestContext.getTrustStorePassword(), KeyStoreFileType.PEM.getPropertyValue(), false,
|
||||
false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPEMTrustStoreNullPassword() throws Exception {
|
||||
assumeThat(x509TestContext.getTrustStorePassword(), equalTo(EMPTY_CHAR_ARRAY));
|
||||
// Make sure that empty password and null password are treated the same
|
||||
X509Util.createTrustManager(
|
||||
x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath(), null,
|
||||
KeyStoreFileType.PEM.getPropertyValue(), false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPEMTrustStoreAutodetectStoreFileType() throws Exception {
|
||||
// Make sure we can instantiate a trust manager from the PEM file on disk
|
||||
X509Util.createTrustManager(
|
||||
x509TestContext.getTrustStoreFile(KeyStoreFileType.PEM).getAbsolutePath(),
|
||||
x509TestContext.getTrustStorePassword(), null, // null StoreFileType means 'autodetect from
|
||||
// file extension'
|
||||
false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadJKSKeyStore() throws Exception {
|
||||
// Make sure we can instantiate a key manager from the JKS file on disk
|
||||
|
@ -222,7 +204,7 @@ public class TestX509Util {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testLoadJKSKeyStoreFileTypeDefaultToJks() throws Exception {
|
||||
public void testLoadJKSKeyStoreAutodetectStoreFileType() throws Exception {
|
||||
// Make sure we can instantiate a key manager from the JKS file on disk
|
||||
X509Util.createKeyManager(
|
||||
x509TestContext.getKeyStoreFile(KeyStoreFileType.JKS).getAbsolutePath(),
|
||||
|
@ -258,16 +240,17 @@ public class TestX509Util {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testLoadJKSTrustStoreFileTypeDefaultToJks() throws Exception {
|
||||
public void testLoadJKSTrustStoreAutodetectStoreFileType() throws Exception {
|
||||
// Make sure we can instantiate a trust manager from the JKS file on disk
|
||||
X509Util.createTrustManager(
|
||||
x509TestContext.getTrustStoreFile(KeyStoreFileType.JKS).getAbsolutePath(),
|
||||
// null StoreFileType means 'autodetect from file extension'
|
||||
x509TestContext.getTrustStorePassword(), null, true, true);
|
||||
x509TestContext.getTrustStorePassword(), null, // null StoreFileType means 'autodetect from
|
||||
// file extension'
|
||||
true, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadJKSTrustStoreWithWrongPassword() throws Exception {
|
||||
public void testLoadJKSTrustStoreWithWrongPassword() {
|
||||
assertThrows(TrustManagerException.class, () -> {
|
||||
// Attempting to load with the wrong key password should fail
|
||||
X509Util.createTrustManager(
|
||||
|
@ -294,7 +277,16 @@ public class TestX509Util {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPKCS12KeyStoreWithWrongPassword() throws Exception {
|
||||
public void testLoadPKCS12KeyStoreAutodetectStoreFileType() throws Exception {
|
||||
// Make sure we can instantiate a key manager from the PKCS12 file on disk
|
||||
X509Util.createKeyManager(
|
||||
x509TestContext.getKeyStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath(),
|
||||
x509TestContext.getKeyStorePassword(),
|
||||
null /* null StoreFileType means 'autodetect from file extension' */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPKCS12KeyStoreWithWrongPassword() {
|
||||
assertThrows(KeyManagerException.class, () -> {
|
||||
// Attempting to load with the wrong key password should fail
|
||||
X509Util.createKeyManager(
|
||||
|
@ -322,7 +314,17 @@ public class TestX509Util {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPKCS12TrustStoreWithWrongPassword() throws Exception {
|
||||
public void testLoadPKCS12TrustStoreAutodetectStoreFileType() throws Exception {
|
||||
// Make sure we can instantiate a trust manager from the PKCS12 file on disk
|
||||
X509Util.createTrustManager(
|
||||
x509TestContext.getTrustStoreFile(KeyStoreFileType.PKCS12).getAbsolutePath(),
|
||||
x509TestContext.getTrustStorePassword(), null, // null StoreFileType means 'autodetect from
|
||||
// file extension'
|
||||
true, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadPKCS12TrustStoreWithWrongPassword() {
|
||||
assertThrows(TrustManagerException.class, () -> {
|
||||
// Attempting to load with the wrong key password should fail
|
||||
X509Util.createTrustManager(
|
||||
|
@ -332,42 +334,42 @@ public class TestX509Util {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultCipherSuitesJava8() throws Exception {
|
||||
public void testGetDefaultCipherSuitesJava8() {
|
||||
String[] cipherSuites = X509Util.getDefaultCipherSuitesForJavaVersion("1.8");
|
||||
// Java 8 default should have the CBC suites first
|
||||
assertThat(cipherSuites[0], containsString("CBC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultCipherSuitesJava9() throws Exception {
|
||||
public void testGetDefaultCipherSuitesJava9() {
|
||||
String[] cipherSuites = X509Util.getDefaultCipherSuitesForJavaVersion("9");
|
||||
// Java 9+ default should have the GCM suites first
|
||||
assertThat(cipherSuites[0], containsString("GCM"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultCipherSuitesJava10() throws Exception {
|
||||
public void testGetDefaultCipherSuitesJava10() {
|
||||
String[] cipherSuites = X509Util.getDefaultCipherSuitesForJavaVersion("10");
|
||||
// Java 9+ default should have the GCM suites first
|
||||
assertThat(cipherSuites[0], containsString("GCM"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultCipherSuitesJava11() throws Exception {
|
||||
public void testGetDefaultCipherSuitesJava11() {
|
||||
String[] cipherSuites = X509Util.getDefaultCipherSuitesForJavaVersion("11");
|
||||
// Java 9+ default should have the GCM suites first
|
||||
assertThat(cipherSuites[0], containsString("GCM"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultCipherSuitesUnknownVersion() throws Exception {
|
||||
public void testGetDefaultCipherSuitesUnknownVersion() {
|
||||
String[] cipherSuites = X509Util.getDefaultCipherSuitesForJavaVersion("notaversion");
|
||||
// If version can't be parsed, use the more conservative Java 8 default
|
||||
assertThat(cipherSuites[0], containsString("CBC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDefaultCipherSuitesNullVersion() throws Exception {
|
||||
public void testGetDefaultCipherSuitesNullVersion() {
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
X509Util.getDefaultCipherSuitesForJavaVersion(null);
|
||||
});
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.security.cert.X509Certificate;
|
|||
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 final class X509TestContext {
|
|||
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 @@ public final class X509TestContext {
|
|||
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 final class X509TestContext {
|
|||
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 @@ public final class X509TestContext {
|
|||
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 final class X509TestContext {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -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 class X509TestContextProvider {
|
|||
public X509TestContext get(X509KeyType caKeyType, X509KeyType certKeyType, char[] keyPassword) {
|
||||
return ctxs.getUnchecked(new CacheKey(caKeyType, certKeyType, keyPassword));
|
||||
}
|
||||
|
||||
static Collection<Object[]> defaultParams() {
|
||||
List<Object[]> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -281,7 +281,7 @@ final class X509TestHelpers {
|
|||
StringWriter stringWriter = new StringWriter();
|
||||
JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter);
|
||||
OutputEncryptor encryptor = null;
|
||||
if (password != null) {
|
||||
if (password != null && password.length > 0) {
|
||||
encryptor =
|
||||
new JceOpenSSLPKCS8EncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC)
|
||||
.setProvider(BouncyCastleProvider.PROVIDER_NAME).setRandom(PRNG).setPasssword(password)
|
||||
|
@ -341,6 +341,23 @@ final class X509TestHelpers {
|
|||
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 @@ final class X509TestHelpers {
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue