안드로이드/개발관련(Kotlin)

안드로이드에서 X.509 인증서, CRL 사용하기

닉네임못짓는사람 2023. 2. 27. 20:04
반응형

이번 글에서는 안드로이드에서 X.509인증서와 CRL을 받아와서 사용해보도록 하자.

 

X.509인증서와 CRL에 대한 내용은 생략하도록 하고, 두 데이터는 전달 받을 때 pem형식으로 받아온다.

pem형식은 아래와 같이 되어있다.

-----BEGIN CERTIFICATE-----
MIIDizCCAnOgAwIBAgIUS8lUTmZGBA+IbTMGkCLVKT6RdMYwDQYJKoZIhvcNAQEL
BQAwNjELMAkGA1UEBhMCa3IxEzARBgNVBAoMClN1d29uVW5pdi4xEjAQBgNVBAMM
CXJvb3RjYVlTWTAeFw0yMTA2MDIyMjEzMDBaFw0yMjA2MDIyMjEzMDBaMDExCzAJ
BgNVBAYTAmtyMRIwEAYDVQQKDAlTdXdvblVuaXYxDjAMBgNVBAMMBTY1OTc5MIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwebQzxF0TOmF2fHI/4y5UobD
rbHFLtgniBxtr6nVkgdbzde6i4Zep8Od7l2LBwIyu29Atavnh6Aahrq4/cw3hT4W
GsxA/yD4MOc8L2+BzlkvFqzuznhF3wBRlU1qmiFbLovI0oPE/I+EGg8OrICFY+I6
oYQYKQKLBjGaZ3QrtfJleJYC0dYC4myZWg/26D0PAodfg5g8fjAaClGhrHvs8Tta
P6b7fR1mWUYbc+S23775hovI3I0h4eYuo3CCkkYmapFpBL8G0eb/x8j4tPU7sA7j
ChHfPHP9/tp1okx2445Z6OEuI+2twVg0sCwUWbljk0NgJhI16wvUeDl+zx1wTwID
AQABo4GVMIGSMAkGA1UdEwQCMAAwHwYDVR0jBBgwFoAUv2QeVPfLh9E2hEUSAK53
bEiBNcYwHQYDVR0OBBYEFNeo0v1pjEwUFUjH4JXX5rbS62WpMAsGA1UdDwQEAwIF
4DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3
Lnplcm9ucy5jb20wDQYJKoZIhvcNAQELBQADggEBAFR8Z7cyFPZkeHJo/rN4rMpI
HaQHmGAzFD5z2DzHJ3qvTMEWL+EokvS/t0j5VkwLYVbkVULCl2ZqwRR4cTv4VZlT
+wqcJiapDlTlzB5GPquydDVLl/9Cr9W0/LPpC6Q9E6bxP48rskuJTjaoA1aZG3rG
K2z5rZLXFzF9pVHQ+heCDkA/mMFb6DHIutoOQgnzigFMcEjyWmnoPeHr1VM6X/TO
/AR1NKR+IsoGZMdMc+pIdBMwPs3zwXNPC4wyK5jGmL1BnDJJmEnpJJMIC+OvQKZ1
25gB8g6MwQPA515G6q70gLTynTniCRM+mg9ldX7TpFEycVXn/YOlm+/RYyYFOOc=
-----END CERTIFICATE-----

 

데이터를 받아올 때에는 안드로이드의 retrofit을 통해 get형태로 받아올것이다.

이렇게 get으로 받아온 데이터를 각각 용도에 맞게 X.509 Certificate또는 CRL로 만들어주어야 한다.

 

방법은 매우 간단하다.

먼저 X509 Certificate부터 확인해보자

fun saveCertificate(certificate: String, path: File?, crl: X509CRL){
    if(path != null){
        var tempFile = File(path, "certificate.crt")
        try{
            val writer = FileWriter(tempFile)
            val buffer = BufferedWriter(writer)
            buffer.write(certificate)
            buffer.close()
        }catch(e: java.lang.Exception){
            e.printStackTrace()
        }

        var cf = CertificateFactory.getInstance("X.509")
        var caIn = BufferedInputStream(FileInputStream(tempFile))
        var ca = caIn.use{
            cf.generateCertificate(it) as X509Certificate
        }

        var kf = KeyFactory.getInstance("RSA")
        var public = kf.generatePublic(X509EncodedKeySpec(ca.publicKey.encoded))

        try{
            if(checkValidify(ca, public, crl)){
                App.prefs.publicKey = Base64Utils.encode(public.encoded)
            }
        }catch (e: Exception){
            Log.e("인증서 유효성 검사", "CRL목록을 받아오지 못했습니다.")
            e.printStackTrace()
        }
    }
}

이 글에선 데이터를 받아서 certficiate.crt파일에 저장해주도록 하였다.

가장 먼저 pem형식으로 된 인증서 내용을 String으로 받게된다.

이후 certificateFactory객체를 만드는데, Instance는 X.509를 지정해준다.

 

위에서 받은 인증서 데이터(String)을 FileInputStream을 사용해 파일에 써주도록 한다.

그리고 이 String을 X509Certificate 객체로 바꾸어주어야하는데,

이때는 위에서 생성한 certificateFactory객체에서 generateCertificate메소드를 사용해서 만들어준다.

이 메소드에 argument로 caIn이 들어가게되고, 이 데이터를 X509Certificate로 캐스트해준다.

 

실제로 인증서를 사용할 때에는 인증서 유효성 검사를 진행해야한다.

인증서 유효성 검사는 인증서 유효기간 검사 -> 인증서 폐기목록(CRL)확인 -> CA의 서명 확인 순으로 진행된다.

 

다음은 CRL을 객체로 만들어 사용하는 법에 대해서 알아보자.

fun saveCRL(response: String?, path: File?): X509CRL{
    var tempFile = File(path, "CRL.crl")
    try{
        val writer = FileWriter(tempFile)
        val buffer = BufferedWriter(writer)
        buffer.write(response)
        buffer.close()
    }catch(e: java.lang.Exception){
        e.printStackTrace()
    }

    val cf = CertificateFactory.getInstance("X.509")
    val crlIn = BufferedInputStream(FileInputStream(tempFile))
    val crl = crlIn.use{
        cf.generateCRL(it) as X509CRL
    }

    try{
        crl.verify(getCAPublicKey())
    }catch (e: Exception){
        Log.e("CRL 서명 검증", "실패")
    }

    return crl
}

여기서도 위와 마찬가지로 CRL을 pem형식으로 받아오고, 이를 파일에 저장해줄것이다.

사실상 코드는 거의다 비슷한데 cf.generateCRL메소드를 사용하고, 이를 X509CRL로 캐스트해준다는 부분만 다르다.

CRL을 사용할 때에도 CA의 서명을 검증해야한다.

 

반응형