/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license 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 jlibs.core.net;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
/**
* @author Santhosh Kumar Tekuti
*/
public class SSLUtil{
public static boolean isClientHello(byte firstByte){
return firstByte==0x80 // TLS Client hello
|| firstByte==0x16; // SSL version 2 compatible hello
}
public static X509Certificate[] getX509CertificateChain(String host, int port) throws GeneralSecurityException, IOException{
final X509Certificate[][] result = new X509Certificate[1][];
TrustManager savingTM = new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] chain, String authType){}
public void checkServerTrusted(X509Certificate[] chain, String authType){
result[0] = chain;
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{ savingTM }, null);
SSLSocketFactory factory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
try{
socket.startHandshake();
}finally{
socket.close();
}
return result[0];
}
public static KeyStore newKeyStore(String type, String file, char password[]) throws SSLException{
try{
KeyStore ks = KeyStore.getInstance(type==null ? KeyStore.getDefaultType() : type);
ks.load(file!=null ? new FileInputStream(file) : null , password!=null?password:null);
return ks;
}catch(Exception ex){
throw new SSLException(ex);
}
}
public static String getKeyStoreType(){
return System.getProperty("javax.net.ssl.keyStoreType", "JKS");
}
public static String getKeyStoreLocation(){
return System.getProperty("javax.net.ssl.keyStore");
}
public static char[] getKeyStorePassword(){
String password = System.getProperty("javax.net.ssl.keyStorePassword");
return password!=null ? password.toCharArray() : null;
}
private static KeyStore defaultKeyStore[];
public static KeyStore defaultKeyStore() throws SSLException{
if(defaultKeyStore==null){
String location = getKeyStoreLocation();
if(location!=null)
defaultKeyStore = new KeyStore[]{ newKeyStore(getKeyStoreType(), location, getKeyStorePassword()) };
else
defaultKeyStore = new KeyStore[]{ null };
}
return defaultKeyStore[0];
}
public static String getTrustStoreType(){
return System.getProperty("javax.net.ssl.trustStoreType", "JKS");
}
public static String getTrustStoreLocation(){
return System.getProperty("javax.net.ssl.trustStore");
}
public static char[] getTrustStorePassword(){
String password = System.getProperty("javax.net.ssl.trustStorePassword");
return password!=null ? password.toCharArray() : null;
}
private static KeyStore defaultTrustStore[];
public static KeyStore defaultTrustStore() throws SSLException{
if(defaultTrustStore==null){
String location = getTrustStoreLocation();
if(location!=null)
defaultTrustStore = new KeyStore[]{ newKeyStore(getTrustStoreType(), location, getTrustStorePassword()) };
else
defaultTrustStore = new KeyStore[]{ null };
}
return defaultTrustStore[0];
}
public static final TrustManager DUMMY_TRUST_MANAGERS[] = new TrustManager[]{
new X509TrustManager(){
public X509Certificate[] getAcceptedIssuers(){
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] chain, String authType){}
public void checkServerTrusted(X509Certificate[] chain, String authType){}
}
};
public static SSLContext newContext(KeyStore keyStore, char[] keyStorePassword, String keyAlias, KeyStore trustStore) throws SSLException, GeneralSecurityException{
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager tm[];
if(trustStore==null)
tm = SSLUtil.DUMMY_TRUST_MANAGERS;
else{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
tm = tmf.getTrustManagers();
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword);
KeyManager km[] = kmf.getKeyManagers();
if(keyAlias!=null){
for(int i=0; i<km.length; i++){
if(km[i] instanceof X509ExtendedKeyManager)
km[i] = new ExtendedAliasKeyManager(km[i], keyAlias);
else if(km[i] instanceof X509KeyManager)
km[i] = new AliasKeyManager(km[i], keyAlias);
}
}
sslContext.init(km, tm , null);
return sslContext;
}
private static SSLContext defaultContext;
public static SSLContext defaultContext() throws SSLException, GeneralSecurityException{
if(defaultContext==null)
defaultContext = newContext(SSLUtil.defaultKeyStore(), SSLUtil.getKeyStorePassword(), null, SSLUtil.defaultTrustStore());
return defaultContext;
}
private static String chooseAlias(X509KeyManager mgr, String serverKeyAlias, String keyType){
PrivateKey key = mgr.getPrivateKey(serverKeyAlias);
if(key!=null){
if(key.getAlgorithm().equals(keyType))
return serverKeyAlias;
else
return null;
}else
return null;
}
// http://svn.apache.org/repos/asf/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeyManager.java
private static final class ExtendedAliasKeyManager extends X509ExtendedKeyManager{
private X509ExtendedKeyManager delegate;
private String serverKeyAlias;
public ExtendedAliasKeyManager(KeyManager mgr, String keyAlias){
this.delegate = (X509ExtendedKeyManager) mgr;
this.serverKeyAlias = keyAlias;
}
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket){
return delegate.chooseClientAlias(keyType, issuers, socket);
}
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket){
return chooseAlias(delegate, serverKeyAlias, keyType);
}
public X509Certificate[] getCertificateChain(String alias){
return delegate.getCertificateChain(alias);
}
public String[] getClientAliases(String keyType, Principal[] issuers){
return delegate.getClientAliases(keyType, issuers);
}
public String[] getServerAliases(String keyType, Principal[] issuers){
return delegate.getServerAliases(keyType, issuers);
}
public PrivateKey getPrivateKey(String alias){
return delegate.getPrivateKey(alias);
}
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine){
return delegate.chooseEngineClientAlias(keyType, issuers, engine);
}
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine){
return chooseAlias(delegate, serverKeyAlias, keyType);
}
}
// http://svn.apache.org/repos/asf/mina/ftpserver/trunk/core/src/main/java/org/apache/ftpserver/ssl/impl/AliasKeyManager.java
private static final class AliasKeyManager implements X509KeyManager{
private X509KeyManager delegate;
private String serverKeyAlias;
public AliasKeyManager(KeyManager mgr, String keyAlias){
this.delegate = (X509KeyManager) mgr;
this.serverKeyAlias = keyAlias;
}
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket){
return delegate.chooseClientAlias(keyType, issuers, socket);
}
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket){
return chooseAlias(delegate, serverKeyAlias, keyType);
}
public X509Certificate[] getCertificateChain(String alias){
return delegate.getCertificateChain(alias);
}
public String[] getClientAliases(String keyType, Principal[] issuers){
return delegate.getClientAliases(keyType, issuers);
}
public String[] getServerAliases(String keyType, Principal[] issuers){
return delegate.getServerAliases(keyType, issuers);
}
public PrivateKey getPrivateKey(String alias){
return delegate.getPrivateKey(alias);
}
}
}