Acception Self-Signed SSL Certificates in Java

Approach 1:  สร้าง SocketFactory ขึ้นมาใหม่

Class 1: NativeTrustManager
สร้าง TrustManager โดยที่ไม่มีการ throw Exception ออกมาเมื่อมีการทำ self-singed SSL certificate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
 
import javax.net.ssl.X509TrustManager;
 
public class NaiveTrustManager implements X509TrustManager{
 
	/**
	* Doesn't throw an exception, so this is how it approves a certificate.
	* @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], String)
	**/
	public void checkClientTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
 
	}
 
	/**
	* Doesn't throw an exception, so this is how it approves a certificate.
	* @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], String)
	**/
	public void checkServerTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
 
	}
 
	/**
	* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
	**/
	public X509Certificate[] getAcceptedIssuers() {
		return null;	// I've seen someone return new X509Certificate[ 0 ]; 
	}
 
}

Class 2: สร้าง SelfSignedSSLSocketFactory ใหม่โดยจำทำการ accept self-signed certificate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package etherdia.gen.util.ssl;
 
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
 
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
 
import org.apache.log4j.Logger;
 
public class SelfSignedSSLSocketFactory {
	private static SSLSocketFactory sslSocketFactory;
	private static Logger logger = Logger
			.getLogger(SelfSignedSSLSocketFactory .class);
 
	/**
	 * Returns a SSL Factory instance that accepts all server certificates.
	 * 
	 * SSLSocket sock = (SSLSocket) getSocketFactory.createSocket(host, 443);
	 * 
	 * @return An SSL-specific socket factory.
	 **/
	public static final SSLSocketFactory getSocketFactory() {
		System.setProperty("javax.net.ssl.trustStore ",
				"org.jiramot.sslutils.NaiveTrustManager");
 
		if (sslSocketFactory == null) {
			try {
				TrustManager[] tm = new TrustManager[] { new NaiveTrustManager() };
				SSLContext context = SSLContext.getInstance("SSL");
				context.init(new KeyManager[0], tm, new SecureRandom());
 
				sslSocketFactory = (SSLSocketFactory) context
						.getSocketFactory();
 
			} catch (KeyManagementException e) {
				logger.error("No SSL algorithm support: " + e.getMessage(), e);
			} catch (NoSuchAlgorithmException e) {
				logger.error(
						"Exception when setting up the Naive key management.",
						e);
			}
		}
		return sslSocketFactory;
	}
 
}

Approach 2: สร้าง Security Provider ใหม่โดย extends java.security.Provider โดยทำการแก้ไขให้ทำการสร้าง NativeTrustManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import java.security.AccessController;
import java.security.KeyStore;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.Security;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactorySpi;
 
/**
 * Provides all secure socket factories, with a socket that ignores problems in
 * the chain of certificate trust. This is good for embedded applications that
 * just want the encryption aspect of SSL communication, without worrying too
 * much about validating the identify of the server at the other end of the
 * connection. In other words, this may leave you vulnerable to a
 * man-in-the-middle attack.
 */
 
public class NaiveTrustProvider extends Provider {
	/** The name of our algorithm **/
	private static final String TRUST_PROVIDER_ALG = "NaiveTrustAlgorithm";
 
	/** Need to refer to ourselves somehow to know if we're already registered **/
	private static final String TRUST_PROVIDER_ID = "NaiveTrustProvider";
 
	/**
	 * Hook in at the provider level to handle libraries and 3rd party utilities
	 * that use their own factory. Requires permission to execute
	 * AccessController.doPrivileged, so this probably won't work in applets or
	 * other high-security jvms
	 **/
 
	public NaiveTrustProvider() {
		super(
				TRUST_PROVIDER_ID,
				(double) 0.1,
				"NaiveTrustProvider (provides all secure socket factories by ignoring problems in the chain of certificate trust)");
 
		AccessController.doPrivileged(new PrivilegedAction() {
			public Object run() {
				put("TrustManagerFactory."
						+ NaiveTrustManagerFactory.getAlgorithm(),
						NaiveTrustManagerFactory.class.getName());
				return null;
			}
		});
	}
 
	/**
	 * This is the only method the client code need to call. Yup, just put
	 * NaiveTrustProvider.setAlwaysTrust() into your initialization code and
	 * you're good to go
	 * 
	 * @param enableNaiveTrustProvider
	 *            set to true to always trust (set to false it not yet
	 *            implemented)
	 **/
 
	public static void setAlwaysTrust(boolean enableNaiveTrustProvider) {
		if (enableNaiveTrustProvider) {
			Provider registered = Security.getProvider(TRUST_PROVIDER_ID);
			if (null == registered) {
				Security.insertProviderAt(new NaiveTrustProvider(), 1);
				Security.setProperty("ssl.TrustManagerFactory.algorithm",
						TRUST_PROVIDER_ALG);
			}
		} else {
			throw new UnsupportedOperationException(
					"Disable Naive trust provider not yet implemented");
		}
	}
 
	/**
	 * The factory for the NaiveTrustProvider
	 **/
	public final static class NaiveTrustManagerFactory extends
			TrustManagerFactorySpi {
		public NaiveTrustManagerFactory() {
		}
 
		protected void engineInit(ManagerFactoryParameters mgrparams) {
		}
 
		protected void engineInit(KeyStore keystore) {
		}
 
		/**
		 * Returns a collection of trust managers that are naive. This
		 * collection is just a single element array containing our
		 * {@link NaiveTrustManager} class.
		 **/
		protected TrustManager[] engineGetTrustManagers() {
			// Returns a new array of just a single NaiveTrustManager.
			return new TrustManager[] { new NaiveTrustManager() };
		}
 
		/**
		 * Returns our "NaiveTrustAlgorithm" string.
		 * 
		 * @return The string, "NaiveTrustAlgorithm"
		 */
		public static String getAlgorithm() {
			return TRUST_PROVIDER_ALG;
		}
	}
}

ที่มา SelfSignedCerts