No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

증상

java 에서 HTTPS 로 remote 사이트에 연결시 다음과 같은 Exception 이 발생

javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
 

원인

서버/클라이언트간 사용하려는 SSL/TLS 버전이 맞지 않음(TLS 1.2 만 지원하는 서버에 1.0로 hand shaking 요청등)

서버가 TLS 1.2 만 사용하는 경우 JDK 1.8 부터 TLS 1.2 가 기본이므로 예전 JDK 를 사용하는 클라이언트는 위 예외가 발생함.

 

해결

먼저 사용하는 연결하려는 사이트와 어떤 TLS 버전을 사용하는지 확인하기 위해 다음 코드를 Hc.java 로 저장한다.

import java.io.IOException;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import javax.net.ssl.HttpsURLConnection;
import javax.security.cert.CertificateException;
public class Hc {
	public static void main(String[] args) throws IOException, CertificateEncodingException, CertificateException {
		if (args == null || args.length == 0) {
			System.err.println("url parameter not suppplied. ");
			System.exit(0);
		}
		
		URL url;
		
		url = new URL(args[0]);
		HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
		System.out.println("Response Code : " + con.getResponseCode());
		System.out.println("Cipher Suite : " + con.getCipherSuite());
		System.out.println("\n");
		Certificate[] certs = con.getServerCertificates();
		for (Certificate cert : certs) {
			javax.security.cert.X509Certificate c = javax.security.cert.X509Certificate.getInstance(cert.getEncoded());
			System.out.println("\tCert Dn : " + c.getSubjectDN());
			System.out.println("\tIssuer Dn : " + c.getIssuerDN());
			System.out.println("\n");
		}
		
		con.disconnect();
	}
}

JAVA
 

  1. 컴파일 

    javac Hc.java
    CODE
  2. 실행

    SSL 버전 확인을 위해 -Djavax.net.ssl.debug=all 추가 필요

    java -Djavax.net.debug=all Hc https://example.com
    CODE

SSLHandshakeException: Received fatal alert: handshake_failure

증상

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.Alerts.getSSLException(Alerts.java:154) at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312) at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)

원인

SSL/TLS 버전이 맞지 않음. 주로 서버가 강력한 암호화를 사용하지만(TLS 1.2) client 의 TLS 가 버전이 낮아서 오래된 알고리즘을 사용할 경우 발생함.

 

다음 명령어로 서버가 사용하는 TLS 버전과 알고리즘을 확인할 수 있음.

$ openssl s_client -connect myserver.com:443
CODE

 

 

해결

  1. Client 의 TLS 버전을 올리고 (JDK 업그레이드등) 강력한 알고리즘을 사용하도록 수정

 

같이 보기

 

Ref