Tag Archives: javax.net.ssl.SSLException: Received fatal alert: protocol_version

[Solved] javax.net.ssl.SSLException: Received fatal alert: protocol_version

javax.net.ssl.SSLException: Received fatal alert: protocol_ version

Questions

Using JDK1.8 development environment and deploying to jdk1.7 server, the following problems appear:

  javax.net.ssl.SSLException: Received fatal alert: protocol_version
	at sun.security.ssl.Alerts.getSSLException(Unknown Source)
	at sun.security.ssl.Alerts.getSSLException(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.recvAlert(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.writeRecord(Unknown Source)
	at sun.security.ssl.AppOutputStream.write(Unknown Source)
	at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
	at java.io.BufferedOutputStream.flush(Unknown Source)
	at org.apache.commons.httpclient.HttpConnection.flushRequestOutputStream(HttpConnection.java:827)
	at org.apache.commons.httpclient.HttpMethodBase.writeRequest(HttpMethodBase.java:1975)
	at org.apache.commons.httpclient.HttpMethodBase.execute(HttpMethodBase.java:993)
	at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:397)
	at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:170)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396)
	at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
	at com.base.util.MySSLProtocolSocketFactory.main(MySSLProtocolSocketFactory.java:115)

Why

On Java 1.8, the default TLS protocol is v1.2. On Java 1.6 and 1.7, tls1.0 is abandoned by default

Solutions

Upgrade JDK version, the most direct. However, due to some project reasons, we can not upgrade the JDK version, we can only solve this problem

1. Set the tlsv1.2 protocol before initiating the request

	System.setProperty("https.protocols", "TLSv1.2");
或  System.setProperty("jdk.tls.client.protocols", "TLSv1.2");
或  java.lang.System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
.....

Did not solve my problem, use system. Setproperty ("javax. Net. Debug", "all") print log, protocol version or tlsv1

2. Specify it as a command line parameter

-Dhttps.protocols=TLSv1.2

The protocol version is still tlsv1 tlsv1

3. Modify Tomcat/bin/Catalina. Bat , and add command parameters

JAVA_OPTS =%JAVA_OPTS%-Dhttps.protocols = TLSv1.2 -Djdk.tls.client.protocols = TLSv1.2

The protocol version is still tlsv1 tlsv1

Modify spring configuration file

<bean
	class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
	<property name="targetObject" value="#{@systemProperties}" />
	<property name="targetMethod" value="putAll" />
	<property name="arguments">
		<props>
			<prop key="https.protocols">TLSv1.2</prop>
		</props>
	</property>
</bean>

The protocol version is still tlsv1 tlsv1

Reference: javax.net.ssl.ssl exception: received fatal Alert: Protocol_ version

My solution:

Using the third party Library: bouncy castle provider

1. Build a tlssocketconnectionfactory

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.security.Principal;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateFactory;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;

import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.security.cert.X509Certificate;

import org.bouncycastle.crypto.tls.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class TLSSocketConnectionFactory extends SSLSocketFactory {

	static {
		if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
			Security.addProvider(new BouncyCastleProvider());
		}
	}

	@SuppressWarnings("resource")
	[@Override](https://my.oschina.net/u/1162528)
	public Socket createSocket(Socket socket, final String host, int port,
			boolean arg3) throws IOException {
		if (socket == null) {
			socket = new Socket();
		}
		if (!socket.isConnected()) {
			socket.connect(new InetSocketAddress(host, port));
		}

		final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(
				socket.getInputStream(), socket.getOutputStream(),
				new SecureRandom());

		return _createSSLSocket(host, tlsClientProtocol);
	}

	[@Override](https://my.oschina.net/u/1162528)
	public String[] getDefaultCipherSuites() {
		return null;
	}

	[@Override](https://my.oschina.net/u/1162528)
	public String[] getSupportedCipherSuites() {
		return null;
	}

	@Override
	public Socket createSocket(String host, int port) throws IOException,
			UnknownHostException {
		throw new UnsupportedOperationException();
	}

	@Override
	public Socket createSocket(InetAddress host, int port) throws IOException {
		throw new UnsupportedOperationException();
	}

	@Override
	public Socket createSocket(String host, int port, InetAddress localHost,
			int localPort) throws IOException, UnknownHostException {
		return null;
	}

	@Override
	public Socket createSocket(InetAddress address, int port,
			InetAddress localAddress, int localPort) throws IOException {
		throw new UnsupportedOperationException();
	}

	private SSLSocket _createSSLSocket(final String host,
			final TlsClientProtocol tlsClientProtocol) {
		return new SSLSocket() {
			private java.security.cert.Certificate[] peertCerts;

			@Override
			public InputStream getInputStream() throws IOException {
				return tlsClientProtocol.getInputStream();
			}

			@Override
			public OutputStream getOutputStream() throws IOException {
				return tlsClientProtocol.getOutputStream();
			}

			@Override
			public synchronized void close() throws IOException {
				tlsClientProtocol.close();
			}

			@Override
			public void addHandshakeCompletedListener(
					HandshakeCompletedListener arg0) {
			}

			@Override
			public boolean getEnableSessionCreation() {
				return false;
			}

			@Override
			public String[] getEnabledCipherSuites() {
				return null;
			}

			@Override
			public String[] getEnabledProtocols() {
				return null;
			}

			@Override
			public boolean getNeedClientAuth() {
				return false;
			}

			@Override
			public SSLSession getSession() {
				return new SSLSession() {

					@Override
					public int getApplicationBufferSize() {
						return 0;
					}

					@Override
					public String getCipherSuite() {
						throw new UnsupportedOperationException();
					}

					@Override
					public long getCreationTime() {
						throw new UnsupportedOperationException();
					}

					@Override
					public byte[] getId() {
						throw new UnsupportedOperationException();
					}

					@Override
					public long getLastAccessedTime() {
						throw new UnsupportedOperationException();
					}

					@Override
					public java.security.cert.Certificate[] getLocalCertificates() {
						throw new UnsupportedOperationException();
					}

					@Override
					public Principal getLocalPrincipal() {
						throw new UnsupportedOperationException();
					}

					@Override
					public int getPacketBufferSize() {
						throw new UnsupportedOperationException();
					}

					@Override
					public X509Certificate[] getPeerCertificateChain()
							throws SSLPeerUnverifiedException {
						return null;
					}

					@Override
					public java.security.cert.Certificate[] getPeerCertificates()
							throws SSLPeerUnverifiedException {
						return peertCerts;
					}

					@Override
					public String getPeerHost() {
						throw new UnsupportedOperationException();
					}

					@Override
					public int getPeerPort() {
						return 0;
					}

					@Override
					public Principal getPeerPrincipal()
							throws SSLPeerUnverifiedException {
						return null;
					}

					@Override
					public String getProtocol() {
						throw new UnsupportedOperationException();
					}

					@Override
					public SSLSessionContext getSessionContext() {
						throw new UnsupportedOperationException();
					}

					@Override
					public Object getValue(String arg0) {
						throw new UnsupportedOperationException();
					}

					@Override
					public String[] getValueNames() {
						throw new UnsupportedOperationException();
					}

					@Override
					public void invalidate() {
						throw new UnsupportedOperationException();
					}

					@Override
					public boolean isValid() {
						throw new UnsupportedOperationException();
					}

					@Override
					public void putValue(String arg0, Object arg1) {
						throw new UnsupportedOperationException();
					}

					@Override
					public void removeValue(String arg0) {
						throw new UnsupportedOperationException();
					}
				};
			}

			@Override
			public String[] getSupportedProtocols() {
				return null;
			}

			@Override
			public boolean getUseClientMode() {
				return false;
			}

			@Override
			public boolean getWantClientAuth() {
				return false;
			}

			@Override
			public void removeHandshakeCompletedListener(
					HandshakeCompletedListener arg0) {
			}

			@Override
			public void setEnableSessionCreation(boolean arg0) {
			}

			@Override
			public void setEnabledCipherSuites(String[] arg0) {
			}

			@Override
			public void setEnabledProtocols(String[] arg0) {
			}

			@Override
			public void setNeedClientAuth(boolean arg0) {
			}

			@Override
			public void setUseClientMode(boolean arg0) {
			}

			@Override
			public void setWantClientAuth(boolean arg0) {
			}

			@Override
			public String[] getSupportedCipherSuites() {
				return null;
			}

			@Override
			public void startHandshake() throws IOException {
				tlsClientProtocol.connect(new DefaultTlsClient() {

					@SuppressWarnings("unchecked")
					@Override
					public Hashtable<Integer, byte[]> getClientExtensions()
							throws IOException {
						Hashtable<Integer, byte[]> clientExtensions = super
								.getClientExtensions();
						if (clientExtensions == null) {
							clientExtensions = new Hashtable<Integer, byte[]>();
						}

						// Add host_name
						byte[] host_name = host.getBytes();

						final ByteArrayOutputStream baos = new ByteArrayOutputStream();
						final DataOutputStream dos = new DataOutputStream(baos);
						dos.writeShort(host_name.length + 3);
						dos.writeByte(0);
						dos.writeShort(host_name.length);
						dos.write(host_name);
						dos.close();
						clientExtensions.put(ExtensionType.server_name,
								baos.toByteArray());
						return clientExtensions;
					}

					@Override
					public TlsAuthentication getAuthentication()
							throws IOException {
						return new TlsAuthentication() {
							@Override
							public void notifyServerCertificate(
									Certificate serverCertificate)
									throws IOException {
								try {
									KeyStore ks = _loadKeyStore();

									CertificateFactory cf = CertificateFactory
											.getInstance("X.509");
									List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>();
									boolean trustedCertificate = false;
									for (org.bouncycastle.asn1.x509.Certificate c : ((org.bouncycastle.crypto.tls.Certificate) serverCertificate)
											.getCertificateList()) {
										java.security.cert.Certificate cert = cf
												.generateCertificate(new ByteArrayInputStream(
														c.getEncoded()));
										certs.add(cert);

										String alias = ks
												.getCertificateAlias(cert);
										if (alias != null) {
											if (cert instanceof java.security.cert.X509Certificate) {
												try {
													((java.security.cert.X509Certificate) cert)
															.checkValidity();
													trustedCertificate = true;
												} catch (CertificateExpiredException cee) {
													// Accept all the certs!
												}
											}
										} else {
											// Accept all the certs!
										}

									}
									if (!trustedCertificate) {
										// Accept all the certs!
									}
									peertCerts = certs
											.toArray(new java.security.cert.Certificate[0]);
								} catch (Exception ex) {
									ex.printStackTrace();
									throw new IOException(ex);
								}
							}

							@Override
							public TlsCredentials getClientCredentials(
									CertificateRequest certificateRequest)
									throws IOException {
								return null;
							}

							private KeyStore _loadKeyStore() throws Exception {
								FileInputStream trustStoreFis = null;
								try {
									KeyStore localKeyStore = null;

									String trustStoreType = System
											.getProperty("javax.net.ssl.trustStoreType") != null ?System
											.getProperty("javax.net.ssl.trustStoreType")
											: KeyStore.getDefaultType();
									String trustStoreProvider = System
											.getProperty("javax.net.ssl.trustStoreProvider") != null ?System
											.getProperty("javax.net.ssl.trustStoreProvider")
											: "";

									if (trustStoreType.length() != 0) {
										if (trustStoreProvider.length() == 0) {
											localKeyStore = KeyStore
													.getInstance(trustStoreType);
										} else {
											localKeyStore = KeyStore
													.getInstance(
															trustStoreType,
															trustStoreProvider);
										}

										char[] keyStorePass = null;
										String str5 = System
												.getProperty("javax.net.ssl.trustStorePassword") != null ?System
												.getProperty("javax.net.ssl.trustStorePassword")
												: "";

										if (str5.length() != 0) {
											keyStorePass = str5.toCharArray();
										}

										localKeyStore.load(trustStoreFis,
												keyStorePass);

										if (keyStorePass != null) {
											for (int i = 0; i < keyStorePass.length; i++) {
												keyStorePass[i] = 0;
											}
										}
									}
									return localKeyStore;
								} finally {
									if (trustStoreFis != null) {
										trustStoreFis.close();
									}
								}
							}

						};
					}

				});
			}
		};
	}
}

2. Send get request demo

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;

import javax.net.ssl.HttpsURLConnection;

import com.base.util.TLSSocketConnectionFactory;


public class HttpsGetDemo {

	public HttpURLConnection createConnection(URI uri) throws IOException {
		URL url = uri.toURL();
		URLConnection connection = url.openConnection();
		HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection;
		httpsURLConnection.setSSLSocketFactory(new TLSSocketConnectionFactory());
		return httpsURLConnection;
	}

	public static void main(String[] args) throws IOException, URISyntaxException {
		HttpsGetDemo httpsGetDemo = new HttpsGetDemo();
		String loginUrl = "https://192.168.1.100/async/device/status/";
	   // String a = "https://192.168.1.100/async/sysscan/add/?target=192.168.1.200&user=admin&pwd=admin";
		HttpURLConnection connection;
		connection = httpsGetDemo.createConnection(new URI(loginUrl));

		if(200 == connection.getResponseCode()){
			//得到输入流
			InputStream is =connection.getInputStream();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len = 0;
			while(-1 != (len = is.read(buffer))){
				baos.write(buffer,0,len);
				baos.flush();
			}
			System.out.println(baos.toString("utf-8"));
			connection.disconnect();
			is.close();
			baos.close();
		} else {
			System.out.println("connection.getResponseCode():"+connection.getResponseCode());
		}
	}
}