개발일지/Kotlin

[Kotlin] Retrofit2에서 Trust anchor for certification path not found 에러가 날 때

낙락장송s 2024. 4. 24. 18:59

정확한 원인과 해당 버전이 맞는지 모르겠는데 Android 10버전 이상에서는 발생하지 않았던 것이 Android 6버전인 단말기에서 SSL handshake error 이슈가 발생한다(같은 API 주소를 경유하는데).

TrustOkHttpClientUtil.kt

import okhttp3.OkHttpClient
import java.lang.Exception
import java.lang.RuntimeException
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import kotlin.Throws

object TrustOkHttpClientUtil {
    val unsafeOkHttpClient: OkHttpClient
    .Builder
        get() = try {
            val trustAllCerts = arrayOf<TrustManager>(
                object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(
                        chain: Array<X509Certificate>,
                        authType: String
                    ) {
                    }

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(
                        chain: Array<X509Certificate>,
                        authType: String
                    ) {
                    }

                    override fun getAcceptedIssuers(): Array<X509Certificate> {
                        return arrayOf()
                    }
                }
            )
            
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            
            val sslSocketFactory = sslContext.socketFactory
            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier { hostname, session -> true }
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
}

HttpClient2.kt

import com.myapp.TrustOkHttpClientUtil.unsafeOkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory


object HttpClient {
    var retrofit: Retrofit? = null
        get() {
            if (field == null) {
                val builder = Retrofit.Builder()
                builder.baseUrl("https://myserver.com/api/")
                builder.addConverterFactory(GsonConverterFactory.create())
                builder.client(unsafeOkHttpClient.build())
                field = builder.build()

            }
            return field
        }
        private set
}

builder.client(unsafeOkHttpClient.build()) // 이 부분 추가

우회 접속 코드용 클래스를 새로 생성하고 임시 조치 했다.(보안상 권장하지 않는다고 함. 그리고 서버 API의 SSL 인증서가 하필 let's encrypt 인증서라 3개월마다 갱신해야함, 그 때마다 인증서를 교체하고 새로 빌드를 해야 하는 상황이 발생. 다른 방법을 찾아봐야지...)