/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.docker.client;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.eclipse.che.commons.lang.NameGenerator;
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 java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
/**
* @author andrew00x
*/
public class DockerCertificates {
public static final String DEFAULT_CA_CERT_NAME = "ca.pem";
public static final String DEFAULT_CLIENT_CERT_NAME = "cert.pem";
public static final String DEFAULT_CLIENT_KEY_NAME = "key.pem";
private static final char[] KEY_STORE_PASSWORD = NameGenerator.generate(null, 12).toCharArray();
public static DockerCertificates loadFromDirectory(String dockerCertDir) {
return loadFromDirectory(Paths.get(dockerCertDir));
}
public static DockerCertificates loadFromDirectory(File dockerCertDir) {
return loadFromDirectory(dockerCertDir.toPath());
}
public static DockerCertificates loadFromDirectory(Path dockerCertDirPath) {
try {
final Path caCertPath = dockerCertDirPath.resolve(DEFAULT_CA_CERT_NAME);
final Path clientKeyPath = dockerCertDirPath.resolve(DEFAULT_CLIENT_KEY_NAME);
final Path clientCertPath = dockerCertDirPath.resolve(DEFAULT_CLIENT_CERT_NAME);
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final Certificate caCert = getCertificate(caCertPath, cf);
final Certificate clientCert = getCertificate(clientCertPath, cf);
final PrivateKey clientKey = getPrivateKey(clientKeyPath);
final KeyStore keyStore = createKeyStore(clientCert, clientKey);
final KeyStore trustStore = createTrustStore(caCert);
final KeyManager[] keyManagers = loadKeyManagers(keyStore, KEY_STORE_PASSWORD);
final TrustManager[] trustManagers = loadTrustManagers(trustStore);
return new DockerCertificates(createSSLContext(keyManagers, trustManagers));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static Certificate getCertificate(Path caCertPath, CertificateFactory cf) throws IOException, CertificateException {
try (InputStream inputStream = Files.newInputStream(caCertPath)) {
return cf.generateCertificate(inputStream);
}
}
private static PrivateKey getPrivateKey(Path clientKeyPath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
final PEMKeyPair clientKeyPair;
try (Reader reader = Files.newBufferedReader(clientKeyPath, Charset.defaultCharset())) {
clientKeyPair = (PEMKeyPair)new PEMParser(reader).readObject();
}
final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(clientKeyPair.getPrivateKeyInfo().getEncoded());
final KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
private static KeyStore createKeyStore(Certificate clientCert, PrivateKey clientKey)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("client", clientCert);
keyStore.setKeyEntry("key", clientKey, KEY_STORE_PASSWORD, new Certificate[]{clientCert});
return keyStore;
}
private static KeyStore createTrustStore(Certificate caCert)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
trustStore.setEntry("ca", new KeyStore.TrustedCertificateEntry(caCert), null);
return trustStore;
}
private static KeyManager[] loadKeyManagers(KeyStore keystore, char[] keyPassword)
throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, keyPassword);
return kmf.getKeyManagers();
}
private static TrustManager[] loadTrustManagers(KeyStore trustStore) throws NoSuchAlgorithmException, KeyStoreException {
final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
return tmf.getTrustManagers();
}
private static SSLContext createSSLContext(KeyManager[] keyManagers, TrustManager[] trustManagers)
throws NoSuchAlgorithmException, KeyManagementException {
final SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(keyManagers, trustManagers, null);
return sslcontext;
}
private final SSLContext sslContext;
private DockerCertificates(SSLContext sslContext) {
this.sslContext = sslContext;
}
public SSLContext getSslContext() {
return sslContext;
}
}