com.facebook.presto.cassandra.util.SslContextProvider Maven / Gradle / Ivy
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.facebook.presto.cassandra.util;
import com.facebook.presto.spi.PrestoException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static com.facebook.airlift.security.pem.PemReader.loadKeyStore;
import static com.facebook.airlift.security.pem.PemReader.readCertificateChain;
import static com.facebook.presto.cassandra.CassandraErrorCode.CASSANDRA_SSL_INITIALIZATION_FAILURE;
import static java.util.Collections.list;
public class SslContextProvider
{
private final Optional keystorePath;
private final Optional keystorePassword;
private final Optional truststorePath;
private final Optional truststorePassword;
public SslContextProvider(
Optional keystorePath,
Optional keystorePassword,
Optional truststorePath,
Optional truststorePassword)
{
this.keystorePath = keystorePath;
this.keystorePassword = keystorePassword;
this.truststorePath = truststorePath;
this.truststorePassword = truststorePassword;
}
public Optional buildSslContext()
{
if (!keystorePath.isPresent() && !truststorePath.isPresent()) {
return Optional.empty();
}
try {
// load KeyStore if configured and get KeyManagers
KeyStore keystore = null;
KeyManager[] keyManagers = null;
if (keystorePath.isPresent()) {
char[] keyManagerPassword;
try {
// attempt to read the key store as a PEM file
keystore = loadKeyStore(keystorePath.get(), keystorePath.get(), keystorePassword);
// for PEM encoded keys, the password is used to decrypt the specific key (and does not
// protect the keystore itself)
keyManagerPassword = new char[0];
}
catch (IOException | GeneralSecurityException ignored) {
keyManagerPassword = keystorePassword.map(String::toCharArray).orElse(null);
keystore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream in = new FileInputStream(keystorePath.get())) {
keystore.load(in, keyManagerPassword);
}
}
validateCertificates(keystore);
KeyManagerFactory keyManagerFactory =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, keyManagerPassword);
keyManagers = keyManagerFactory.getKeyManagers();
}
// load TrustStore if configured, otherwise use KeyStore
KeyStore truststore = keystore;
if (truststorePath.isPresent()) {
truststore = loadTrustStore(truststorePath.get(), truststorePassword);
}
// create TrustManagerFactory
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(truststore);
// get X509TrustManager
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if ((trustManagers.length != 1) || !(trustManagers[0] instanceof X509TrustManager)) {
throw new RuntimeException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
// create SSLContext
SSLContext result = SSLContext.getInstance("SSL");
result.init(keyManagers, new TrustManager[] {trustManager}, null);
return Optional.of(result);
}
catch (GeneralSecurityException | IOException e) {
throw new PrestoException(CASSANDRA_SSL_INITIALIZATION_FAILURE, e);
}
}
public KeyStore loadTrustStore(File trustStorePath, Optional trustStorePassword)
throws IOException, GeneralSecurityException
{
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
try {
// attempt to read the trust store as a PEM file
List certificateChain = readCertificateChain(trustStorePath);
if (!certificateChain.isEmpty()) {
trustStore.load(null, null);
for (X509Certificate certificate : certificateChain) {
X500Principal principal = certificate.getSubjectX500Principal();
trustStore.setCertificateEntry(principal.getName(), certificate);
}
return trustStore;
}
}
catch (IOException | GeneralSecurityException ignored) {
}
try (InputStream inputStream = new FileInputStream(trustStorePath)) {
trustStore.load(inputStream, trustStorePassword.map(String::toCharArray).orElse(null));
}
return trustStore;
}
public void validateCertificates(KeyStore keyStore) throws GeneralSecurityException
{
for (String alias : list(keyStore.aliases())) {
if (!keyStore.isKeyEntry(alias)) {
continue;
}
Certificate certificate = keyStore.getCertificate(alias);
if (!(certificate instanceof X509Certificate)) {
continue;
}
try {
((X509Certificate) certificate).checkValidity();
}
catch (CertificateExpiredException e) {
throw new CertificateExpiredException("KeyStore certificate is expired: " + e.getMessage());
}
catch (CertificateNotYetValidException e) {
throw new CertificateNotYetValidException("KeyStore certificate is not yet valid: " + e.getMessage());
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy