정리사항 42 - 수신한 인증서 체인검증(적용)
*레트로핏2사용하여 수신한 인증서 체인검증
-체인검증 적용
//인증서변환
//base64문자열 byte변환
byte[] encodedCert = Base64.decode(certData, Base64.DEFAULT);
ByteArrayInputStream inputStream = new ByteArrayInputStream(encodedCert);
CertificateFactory certFactory = null;
try {
certFactory = CertificateFactory.getInstance("X.509");
X509Certificate convertCertificate = (X509Certificate) certFactory.generateCertificate(inputStream);
//인증서 검증
verificationCA(convertCertificate);
...
-체인검증 메서드
//인증서 검증
public void verificationCA(X509Certificate serverCertificate) throws CertificateException, NoSuchAlgorithmException, IOException {
//클라이언트 인증서
InputStream clientCertStream = getResources().openRawResource(R.raw.test1);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
X509Certificate clientCertificate = (X509Certificate) certificateFactory.generateCertificate(clientCertStream);
clientCertStream.close();
//(테스트)네이버인증서
InputStream naverCertStream = getResources().openRawResource(R.raw.naver);
X509Certificate naverCertificate = (X509Certificate) certificateFactory.generateCertificate(naverCertStream);
naverCertStream.close();
try {
// 인증서 체인 검증을 위한 TrustManagerFactory 초기화
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(null, null);
keystore.setCertificateEntry("ca", clientCertificate);
trustManagerFactory.init(keystore);
// SSLContext 초기화
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
// 서버 인증서 검증
X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
X509Certificate[] chain = new X509Certificate[] { serverCertificate };
// //(테스트)네이버인증서
// X509Certificate[] chain = new X509Certificate[] { naverCertificate };
trustManager.checkServerTrusted(chain, "RSA");
// 인증서 체인 검증 성공
Log.e("E", "[인증서 체인 검증 성공]");
} catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
// 인증서 체인 검증 실패
Log.e("E", "[인증서 체인 검증 실패]");
} catch (IOException e) {
throw new RuntimeException(e);
}
}//verificationCA
*브라우저 인증서 저장(테스트용)
-브라우저 URL창 자물쇠
-이 연결은 안전합니다.
-인증서가 유효함
-인증서뷰어 - 세부정보
-인증서계층 - 선택 - 내보내기
*SSLContext 초기화
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
SSLContext는 SSL 프로토콜을 사용하여 네트워크 통신을 보호하기 위한 라이브러리입니다. SSL은 Secure Socket Layer의 약자로, 전송 계층 보안(Transport Layer Security, TLS)과 함께 인터넷 상에서 데이터를 안전하게 전송하기 위한 프로토콜입니다. SSL은 데이터를 암호화하고 인증서를 통해 서버의 신원을 확인하는 등의 보안 기능을 제공합니다.
SSLContext는 SSL/TLS 연결에 필요한 암호화 알고리즘, 프로토콜 버전, 인증서 및 키 관리 등을 설정하는 데 사용됩니다. SSLContext를 초기화하여 SSL/TLS 연결을 설정하면, 클라이언트와 서버 간의 통신이 보안적으로 안전하게 이루어질 수 있습니다. 이를 통해 중간자 공격 및 데이터 도난 등의 보안 위협으로부터 통신을 보호할 수 있습니다. 따라서 SSLContext를 초기화하는 것은 네트워크 보안을 강화하는 데 중요한 역할을 합니다.
*X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
이 코드는 X.509 인증서를 신뢰하는 TrustManager를 생성하는데 사용됩니다.
먼저, trustManagerFactory 변수는 TrustManagerFactory 클래스의 인스턴스입니다. TrustManagerFactory는 SSL/TLS 연결에서 인증서를 관리하는데 사용됩니다.
getTrustManagers() 메서드는 TrustManagerFactory에서 사용 가능한 TrustManager 배열을 반환합니다. 이 배열에는 하나 이상의 TrustManager가 포함될 수 있습니다. 보통, 하나 이상의 TrustManager를 사용하여 서로 다른 타입의 인증서를 처리하는데 사용됩니다.
위 코드에서는 [0] 인덱스를 사용하여 배열의 첫 번째 TrustManager를 선택합니다. 이 TrustManager는 X.509 인증서를 사용하여 서버 인증을 검증하는 X509TrustManager 인스턴스입니다.
따라서 위 코드는 X.509 인증서를 신뢰하는 X509TrustManager 인스턴스를 생성합니다. 이 TrustManager는 SSL/TLS 연결에서 서버 인증서를 검증하는 데 사용됩니다.
* trustManager.checkServerTrusted(chain, "RSA");
-checkServerTrusted(X509Certificate[] chain, String authType)
피어에서 제공한 부분 또는 전체 인증서 체인이 제공되면 신뢰할 수 있는 루트에 대한 인증서 경로를 만들고 인증 유형에 따라 서버 SSL 인증에 대해 유효성을 검사하고 신뢰할 수 있는 경우 반환합니다.
*참고
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class CertificateValidation {
public static void main(String[] args) throws Exception {
// Load server certificate from response
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder()
.url("https://example.com")
.build();
Response response = client.newCall(request).execute();
X509Certificate serverCert = (X509Certificate) response.handshake().peerCertificates().get(0);
// Load trusted certificate from raw folder
InputStream trustedCertInputStream = CertificateValidation.class.getResourceAsStream("/trusted_cert.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate trustedCert = cf.generateCertificate(trustedCertInputStream);
// Create trust manager with trusted certificate
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("trustedCert", trustedCert);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
X509TrustManager trustManager = (X509TrustManager) trustManagerFactory.getTrustManagers()[0];
// Validate server certificate chain
X509Certificate[] chain = new X509Certificate[] { serverCert };
trustManager.checkServerTrusted(chain, "RSA");
// If no exception is thrown, the chain is valid
System.out.println("Certificate chain is valid.");
}
}
https://developer.android.com/reference/javax/net/ssl/X509TrustManager
X509TrustManager | Android Developers
developer.android.com