OpenJDK建⽴SSL失败的问题
跟第三⽅⽀付之间通信通常采⽤的https,⽽https⽤到了SSL,java中⼀般都是SSLSocket完成通信的。本来之前⼀直⽤得好好的,最近突然在服务器上,报了以下错误:
jdk怎么使用java.security.ProviderException: java.security.KeyException
这个错误在⽹上了下,竟然没有相关资料。没办法,只能⾃⼰跟踪代码,最后通过跟踪代码,发现在sslsock.startHandshake();时报错了。了解SSL的⼀看就知道这个异常发⽣在SSL三次握⼿上,天哪,这可以是JDK内部的错误啊,要改也改不了啊。其实吧,这已经是第⼆次遇到这个错误了,之前也遇到过⼀次,那次因为要发⽣产环境,没有过多时间分析这个问题,初步定为也是JDK的问题,但不知道出现在JDK什么地⽅,后来把JDK做了降级就好了。(因为我们之前也⽤过同⼀个第三⽅⽀付,⽽另⼀台服务器上是好的,通过对⽐之后发现,除了JDK不⼀样,其他都⼀样,不⾏的那台服务器就是JDK版本⾼了,我记得好像是jdk1.7_85,⽽没有问题的那台服务器是jdk1.7_71,后来换成jdk1.7_71果然好了,不过⼀直不知道深层次的原因。)
于是把关键字sslsock.startHandshake()  再加java.security.KeyException,在⽹上⼜搜了⼀下,终于折腾了⽼半天,在⼀个论坛⾥到了点眉⽬,⼤概意思是操作系统的问题。我们⽤的是Cent OS,那个帖⼦上说的是乌班图系统的⼀个BUG。然后再深究看到底是什么问题,最后发现,原来不是JDK的问题,
⽽是nss包的问题。
真正的原因是Open JDK在使⽤SSL时,⽀持哪些协议和加密算法是拿的之前Oracle的协议列表。⽽在真正使⽤协议和算法的时候(SSL的三次握⼿)使⽤的却是nss包⾥的provider,这就导致了JDK在通知服务器时说他⽀持这些算法列表,等服务器返回需要真正⽤的时候nss ⾥没有这个算法,就会报这个异常。
要解决这个问题有两种⽅式,第⼀种就是我之前把JDK降级处理,因为⽼版本的JDK⽀持的算法列表⽐较少,可能跟nss⾥⽀持的⼀致,就没有问题。第⼆种就是把nss包升级,⼀般JDK1.7的nss升级到3.16.1以上就没问题了。
通常遇到这个异常时,查下nss版本,升级下就可以了。
查看nss版本:rpm -q nss
升级nss:yum update -y nss
对了,这个问题还就是Open JDK才有的,因为Open JDK依赖nss,⽽Oracle JDK因为有⾃⼰的EC,不依赖nss,所以没有这个问题。因为现在android⽤的都是Open JDK,服务端也⽤Open JDK统⼀起来能避免不少问题。⽽且Open JDK也是未来的趋势,还是建议使⽤的。对了,貌似在Open JDK 1.8
⾥⾯这个BUG已经解决了。