본문 바로가기
Programming/Android

Trust anchor for certification path not found 해결하기

by 유주원 2021. 11. 25.

Android 앱에서 https 연결을 시도하려고 할 때 Trust anchor for certification path not found 라는 에러가 발생하면서 연결이 실패했다.

 

서비스 중인 앱이라 부랴부랴 원인을 찾기 시작함.

원인은 해당 앱에 신뢰성 있는 인증서를 찾지 못했기 때문인 것 같다.

 

우선 첫번째로 TrustManager를 사용해서 인증서 회피를 시도했다.

 

 TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {  
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
            return new java.security.cert.X509Certificate[]{};  
        }  
  
        @Override  
        public void checkClientTrusted(  
                java.security.cert.X509Certificate[] chain,  
                String authType)  
                throws java.security.cert.CertificateException {  
            // TODO Auto-generated method stub  
        }  
  
        @Override  
        public void checkServerTrusted(  
                java.security.cert.X509Certificate[] chain,  
                String authType)  
                throws java.security.cert.CertificateException {  
            // TODO Auto-generated method stub  
        }  
    }};  
  
    // Install the all-trusting trust manager  
    try {  
        SSLContext sc = SSLContext.getInstance("TLS");  
        sc.init(null, trustAllCerts, new java.security.SecureRandom());  
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());  
    } catch (Exception e) {  
        e.printStackTrace();  
    }

 

위의 코드를 적용 후 https에 접속하면 정상적으로 결과를 받아올 수 있는 것을 확인했다. 하지만 아래의 무시무시한 검색 결과를 발견!!

 

X509TrustManager 사용시 안전하지 않은 인터페이스를 구현했을 경우 앱이 차단될 수 있다고 구글에서 경고한 것이다.

 

코드 상에서도 보면 checkServerTrusted의 구현 부분에 아무런 코드가 없어도 동작이 잘되고 있는 것을 확인해 볼 수가 있다. 실제로는 저 부분에 신뢰할 수 있는 인증서인가를 확인할 코드를 구현해야 하는 것 같다.

 

여러가지 조건 등 (능력 부족) 으로 첫 번째 방법은 포기!!

 

두 번째 방법으로 다시 https 접근을 시도해 본다.

본래의 에러 내용이 신뢰할 수 없는 인증서를 찾지 못한것이기 때문에 신뢰할 수 있는 인증서를 앱 내에 등록하면 되지 않을까?

그래서 여러가지 찾아 봄...

 

우선 접속하고자 하는 url을 통해 인증서 정보를 가져오도록 하자.

 

$> openssl s_client -connect [접속하고자 하는 url]:443

 

위 결과를 실행시키면 아래와 같이 인증서 정보가 나타나게 된다.

 

depth=1 C = BE, O = GlobalSign nv-sa, CN = GlobalSign RSA OV SSL CA 2018

 

CN이 GlobalSign RSA OV SSL CA 2018로 되어 있다. 인터넷에서 찾아보자. (query : GlobalSign RSA OV SSL CA 2018 download)

 

와우 ~ 아래의 url을 찾아 냈다.

 

http://certificate.fyicenter.com/7530_GlobalSign_RSA_OV_SSL_CA_2018_Certificate-F8EF7FF2CD7867A8DE6F8F248D88F1870302B3EB.html

해당 url에 접속한 후 PEM Format 정보를 가져오자.

 

----BEGIN CERTIFICATE----
~~~
----END CERTIFICATE----

해당 정보를 복사한 후 안드로이드 res < raw < mycert.crt 의 파일로 만들었다.

이렇게 만든 인증 파일을 이용하는 코드를 구현해 보자.

 

CertificateFactory cf;
Certificate ca;
String result = "";
InputStream caInput;
try {
	cf = CertificateFactory.getInstance("X.509");

	caInput = ApplicationController.getAppContext().getResources()
                    .openRawResource(R.raw.mycert);
	ca = cf.generateCertificate(caInput);

	// Create a KeyStore containing our trusted CAs
	String keyStoreType = KeyStore.getDefaultType();
	KeyStore keyStore = KeyStore.getInstance(keyStoreType);
	keyStore.load(null,null);
	keyStore.setCertificateEntry("ca", ca);

	// Create a TrustManager that trusts the CAs in our KeyStore
	String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
	tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
	tmf.init(keyStore);

	// Create an SSLContext that uses our TrustManager
	sslContext = SSLContext.getInstance("TLS");
	sslContext.init(null, tmf.getTrustManagers(), new java.security.SecureRandom());
	caInput.close();

 	URL url = new URL("접속하려는 https url");
 	HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
	urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
	InputStream in = urlConnection.getInputStream();
	result = new BufferedReader(new InputStreamReader(in, "euc-kr"))
                    .lines().parallel().collect(Collectors.joining("\n"));
	System.out.println(result);
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException | KeyManagementException e) {
    e.printStackTrace();
}

정상적으로 데이터를 받아 오는 걸 확인 할 수가 있다.

 

참고 url : https://developer.android.com/training/articles/security-ssl?hl=ko#UnknownCa