JSSE(Java Secure Socket Extension, J2SE 1.4 이후 버전에는 JSSE가 포함되어 있다.)를 이용하여 SSL 연결을 시도할 때 아래와 같은 exception이 발생할 수 있다. 공인 인증기관에서 받은 인증서가 아닌 개인 인증서를 사용하는 경우 많이 발생할 수 있다.

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


그렇다면 어떻게 해야 하느냐?? 여러 가지 방법이 있지만, 간단한 방법은 서버의 인증서를 신뢰할 수 있는 인증서 목록(KeyStore)에 추가하면 된다. 인증서를 추가하려면 우선 인증서를 받아야겠다. 인증서는 첨부된 파일(installcert.java)을 받아서 컴파일하고 실행하면 된다. 실행시키면 아래와 같은 화면이 나타날 것이다. "ecc.fedora.redhat.com" 부분에 인증서를 원하는 서버의 ip와 port를 써주면 된다.


% java InstallCert ecc.fedora.redhat.com
Loading KeyStore C:\Program Files\Java\jre1.5.0_08\lib\security\cacerts...
Opening connection to ecc.fedora.redhat.com:443...
Starting SSL handshake...

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1476)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:174)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:168)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:846)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:106)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:815)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1025)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1038)
at InstallCert.main(InstallCert.java:63)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:221)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:145)
at sun.security.validator.Validator.validate(Validator.java:203)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:172)
at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:158)
at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(SSLContextImpl.java:320)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:839)
... 7 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:236)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:194)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:216)
... 13 more

Server sent 2 certificate(s):

1 Subject CN=ecc.fedora.redhat.com, O=example.com, C=US
Issuer CN=Certificate Shack, O=example.com, C=US
sha1 2e 7f 76 9b 52 91 09 2e 5d 8f 6b 61 39 2d 5e 06 e4 d8 e9 c7
md5 dd d1 a8 03 d7 6c 4b 11 a7 3d 74 28 89 d0 67 54

2 Subject CN=Certificate Shack, O=example.com, C=US
Issuer CN=Certificate Shack, O=example.com, C=US
sha1 fb 58 a7 03 c4 4e 3b 0e e3 2c 40 2f 87 64 13 4d df e1 a1 a6
md5 72 a0 95 43 7e 41 88 18 ae 2f 6d 98 01 2c 89 68

Enter certificate to add to trusted keystore or 'q' to quit: [1]


실행시키면 SSL handshake가 일어난다. 화면에는 exception 부분도 출력된다. exception이 출력되는 이유는 서버에서 사용하는 인증서가 없기 때문에 SSL 연결을 성공할 수 없기 때문이다. 자, 인증서를 받자. 그리고 화면에는 trusted KeyStore에 인증서를 추가할 것인지 묻고 있다. sha1과 md5를 확인해서 올바른 인증서인지 확인한 다음, 올바른 인증서인 경우 "1"을 입력해서 인증서를 받으면 되고, 받고 싶지 않은 경우는 "q"를 입력해서 프로그램을 종료시키면 된다. 인증서를 받게 되면 아래와 같은 화면이 출력되고, "jssecacerts" 파일로 인증서가 저장된다.


[
[
Version: V3
Subject: CN=ecc.fedora.redhat.com, O=example.com, C=US
Signature Algorithm: MD5withRSA, OID = 1.2.840.113549.1.1.4

Key: SunPKCS11-Solaris RSA public key, 1024 bits (id 5158256, session object)
modulus: 1402933022884660852748661816869706021655226675890
635441166580364941191074987345500771612454338502131694873337
233737712894815966313948609351561047977102880577818156814678
041303637255354084762814638611185951230474669455913908815827
173696651397340074281578017567044868711049821409365743953199
69584127568303024757
public exponent: 65537
Validity: [From: Wed Jan 18 13:16:12 PST 2006,
To: Wed Apr 18 14:16:12 PDT 2007]
Issuer: CN=Certificate Shack, O=example.com, C=US
SerialNumber: [ 0f]

Certificate Extensions: 2
[1]: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
SSL server
]

[2]: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
Key_Encipherment
]

]
Algorithm: [MD5withRSA]
Signature:
0000: 6D F4 2A 63 76 2A 05 70 A2 21 0E 1E 4A 31 BE 6B m.*cv*.p.!..J1.k
0010: 15 64 D8 BB 35 36 82 B0 0D 2A 96 FA 7A 9F A1 59 .d..56...*..z..Y
0020: CA 90 C3 28 C5 A6 9B 59 05 3B EB B2 8D C9 5E 38 ...(...Y.;....^8
0030: 62 ED 1A D7 93 DF 2A A5 D6 54 94 23 15 A2 0C E5 b.....*..T.#....
0040: 13 40 2C 3E 59 E4 2A EB 51 AC 9E 28 44 23 87 B1 .@,>Y.*.Q..(D#..
0050: 34 0B AC F3 E0 39 CA B8 35 B4 78 07 BF 28 4C C4 4....9..5.x..(L.
0060: 9A 2B A3 E9 04 26 78 19 F0 62 EA 0A B5 BB DC 0B .+...&x..b......
0070: 90 59 E7 77 90 F8 BC 8A 1B 74 4B 4D C1 F8 3B 6C .Y.w.....tKM..;l

]

Added certificate to keystore 'jssecacerts' using alias 'ecc.fedora.redhat.com-1'


이제 이 인증서를 어떻게 사용할까?? 여기에도 몇 가지 방법이 있다. 가장 간단한 방법은 "$JAVA_HOME/jre/lib/security" 폴더에 받은 인증서 파일을 복사하는 방법이다. (이 경우는 파일명을 변경하면 인증서를 찾지 못 한다. 원인은 아직까지는 잘 모르겠다. 본인은 이 방법 대신 다음 방법을 사용한다.)
그리고 다른 방법은 인증서를 원하는 위치로 옮기고 (이 경우는 파일명을 변경해도 상관 없다.) SSL 연결이 필요한 java 명령을 실행할 때, VM 옵션으로 "-Djavax.net.ssl.trustStore=인증서의 경로(인증서 파일명 포함)"를 추가해주면 된다. 다시 첨부 파일을 실행시켰을 때, 아까와는 다른 아래와 같은 화면이 출력되면 성공이다.


% java InstallCert ecc.fedora.redhat.com
Loading KeyStore jssecacerts...
Opening connection to ecc.fedora.redhat.com:443...
Starting SSL handshake...

No errors, certificate is already trusted

Server sent 2 certificate(s):

1 Subject CN=ecc.fedora.redhat.com, O=example.com, C=US
Issuer CN=Certificate Shack, O=example.com, C=US
sha1 2e 7f 76 9b 52 91 09 2e 5d 8f 6b 61 39 2d 5e 06 e4 d8 e9 c7
md5 dd d1 a8 03 d7 6c 4b 11 a7 3d 74 28 89 d0 67 54

2 Subject CN=Certificate Shack, O=example.com, C=US
Issuer CN=Certificate Shack, O=example.com, C=US
sha1 fb 58 a7 03 c4 4e 3b 0e e3 2c 40 2f 87 64 13 4d df e1 a1 a6
md5 72 a0 95 43 7e 41 88 18 ae 2f 6d 98 01 2c 89 68

Enter certificate to add to trusted keystore or 'q' to quit: [1]
q
KeyStore not changed


AND