• 我是如何解决java.security.cert.CertPathValidatorException异常的


    问题来了

    昨天,我还在我的工位上愉快的敲的代码,有位开发组的同事Z给我发消息。

    开发组同事Z:大哥,这个PKI的登录功能是你做的吗?

    我:是呀!N年前的事了。。。

    开发组同事Z:PKI登录功能出问题了!有位客户使用他的PKI登录我们做的系统,登录时报错,换了几台电脑也不行。但是他使用他的PKI能登录其他的系统。能帮忙看一下吗,我找过好多同事看过了,他们看了下,都不知道如何入手

    我:报错是报什么错?能具体的描述下吗?

    开发组同事Z:访问系统时,能弹出证书的选择框,选择完证书后,Chrome浏览器的报错信息是:ERR_SSL_PROTOCOL_ERROR

    我:行吧,我待会过去瞧瞧

    问题分析

    之前在配置tomcat的SSL时,我已经把客户证书的根证书已经导入到服务器信任证书列表内(配置见附录),“能弹出证书的选择框”说明服务器端是能识别出客户证书,但是为什么在登录的过程中,就报错了,可能有如下的几种原因:

    1. 服务器端的证书和服务器端的信任证书配置有误;(我一直以为是服务器端证书中的IP地址和服务器的IP不一致,后来才发现这个是不可能的)
    2. 登录过程中,tomcat能读取到客户端的证书,在程序处理的过程中,拒绝该证书;(客户端的证书的格式不被服务器端接受)
    3. 客户端证书过期了?(通过上面的描述好像不是这个错误)
    4. tomcat或者JDK有问题?(这个不太可能,其他用户使用PKI能登录呀)

    解决问题

    博主当时也是有点懵逼,不知道该怎么解决这个问题。好在博主有敢于尝试的精神,决定一个一个试一下。

    重新安装服务器端证书

    首先使用keytool工具生成服务器端证书,再使用keytool导入客户的根证书到服务器端的信任证书库中。然后把服务器端证书和服务器端的信任证书库放入tomcat,配置、重启tomcat(这里省略了具体的配置过程,具体的配置步骤见附录)。经过一番尝试,发现选择完证书还是报错。又经过一番折腾,还是没有找过是啥原因,正在灰心丧气的时候,灵机一动,程序员不是应该从日志中找错误吗?于是从网上找了一下java中如何开启SSL的日志信息。

    日志带来曙光

    在tomcat中加入JVM参数: -Djavax.net.debug=SSL,handshake,data,trustmanager,重启tomcat。使用客户的证书重新登录,看到后台打印出了很多的日志信息,浏览了一遍后,发现了如下的异常:

    http-nio-8443-exec-4, fatal error: 46: General SSLEngine problem
    sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: algorithm constraints check failed
    %% Invalidated:  [Session-7, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
    http-nio-8443-exec-4, SEND TLSv1.2 ALERT:  fatal, description = certificate_unknown
    http-nio-8443-exec-4, WRITE: TLSv1.2 Alert, length = 2
    http-nio-8443-exec-4, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    http-nio-8443-exec-4, called closeOutbound()
    http-nio-8443-exec-4, closeOutboundInternal()
    

    拿着这个异常信息java.security.cert.CertPathValidatorException: algorithm constraints check failed去google上搜索了一下,找到了如下的这两个网站上的解决方法:

    于是乎,按照上面的描述修改了JDK的配置信息,重启tomcat,使用证书登录,居然能正常登录了。心中暗自高兴了好一会儿,满满的成就感,想不到居然修改了一点配置就解决了......在高兴之余,想着搞清楚这到底是怎么一回事!接下来,容我慢慢道来。

    刨根到底

    到底是做了什么神奇的操作,就解决这问题了呢!首先找到JDK安装目录下的这个文件:

    $JAVA_HOME/jre/lib/security/java.security
    

    然后修改其中的两项配置(为了确保不出报错,把这两项禁用的算法全置为空):

    # 处理证书路径时禁用的算法
    jdk.certpath.disabledAlgorithms=
    # 处理SSL/TLS时禁用的算法
    jdk.tls.disabledAlgorithms=
    

    然后重启tomcat就行了。

    先看一下禁用的算法的语法,如下:

    # 总体的语法
    禁用的算法1, 禁用的算法2, 禁用的算法3...
    # 禁用的每一项算法语法
    算法名称 keySize 操作符 数值值
    

    例如:DSA表示禁用DSA算法,RSA keySize < 2048表示禁用密钥长度小于2048的RSA算法,RSA keySize > 1024, RSA keySize < 2048表示禁用密钥长度大于1024小于2048的RSA算法。

    后来,仔细看了一下日志,发现在客户证书的信息有这么一行:

    Signature Algorithm: SHA1withRSA, OID = 1.2.***.11***9.1.1.*
    
    Key:  Sun RSA public key, 1023 bits
    

    客户证书的密钥长度居然是1023,而JDK8中为了安全性默认禁用了密钥长度小于2048的算法。最终修改的配置如下:

    jdk.certpath.disabledAlgorithms=MD2, RSA keySize < 512
    

    问题就这样解决了,哈哈!!!

    总结

    有时遇到问题,真的是让人摸不到头脑,这时别着急,把自己能想到的方法先尝试一遍,说不定就能行了呢。遇到问题首先可以借助日志来分析问题(就像上面那样打开JDK的SSL的调试日志的开关),通过日志大概就能定位到时哪里出问题了。在实际的开发中,很多程序猿基本上不会记录日志,稍微好一点的可能会在控制台使用System.out.println(xxxx)输出日志,不习惯使用像log4j这样的日志框架来记录日志。有人会说,出了问题,我可以直接debug呀!你有没想过在生产环境中,你还能用IDE来进行调试吗?

    附录

    tomcat的SSL配置

    编辑conf/server.xml文件加入如下的配置:

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"
                   maxThreads="150" scheme="https" secure="true"
                   clientAuth="true" sslProtocol="TLS"
                   keystoreFile="${catalina.base}/server.ks" keystorePass="123456"
                   truststoreFile ="${catalina.base}/server_trust.ks" 
               	   truststorePass="123456"/>
    

    说明:

    • clientAuth为true表示开启SSL双向认证
    • keystoreFile指定服务器端的证书位置
    • truststoreFile指定服务器端信任证书库

    服务器端证书配置

    1. 生成服务器端证书

      keytool -genkeypair -v -alias server -keyalg RSA -validity 3650 -keystore ./server.ks  -storepass 123456 -keypass 123456 -dname "CN=192.168.2.89,OU=zfx,O=zfx,L=gz,ST=gd,C=cn"
      
    2. 导出服务器端证书

      keytool -exportcert -alias server  -keystore ./server.ks  -file ./server.cer  -storepass 123456
      
    3. 导入服务器端证书到服务器信任证书列表

      keytool -importcert -alias serverca  -keystore ./server_trust.ks  -file ./server.cer  -storepass 123456
      
    4. 导入客户根证书到服务器信任证书列表

      keytool -importcert -alias urootca -keystore ./server_trust.ks  -file ./uroot.cer  -storepass 123456
      

    使用如下的命令查看信任的证书信息:

    keytool -list -keystore ./server_trust.ks -storepass 123456
    

    Keytool命令常用参数

    • -genkeypair在用户主目录中创建一个默认文件”.keystore”,还会产生一个mykey的别名,mykey中包含用户的公钥、私钥和证书(在没有指定生成位置的情况下,keystore会存在用户系统默认目录)
    • -alias 产生别名 每个keystore都关联这一个独一无二的alias,这个alias通常不区分大小写
    • -keystore 指定密钥库的路径(产生的各类信息将不在.keystore文件中)
    • -keyalg 指定密钥的算法 (如 RSA,DSA,默认值为:DSA)
    • -validity 指定创建的证书有效期多少天(默认 90)
    • -keysize 指定密钥长度 (默认 1024
    • -storepass 指定密钥库的密码(获取keystore信息所需的密码)
    • -keypass 指定别名条目的密码(私钥的密码)
    • -dname 指定证书发行者信息 其中: “CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名 称,ST=州或省份名称,C=单位的两字母国家代码”
    • -list 显示密钥库中的证书信息如:keytool -list -v –keystore path/to/keystore -storepass password
    • -v 显示密钥库中的证书详细信息
    • -exportcert 导出指定别名的证书,如:keytool - exportcert -alias theAlias -keystore path/to/keystore -file path/to/keystore/cert -storepass pass
    • -file 参数指定导出到文件的文件名
    • -delete 删除密钥库中某条目 keytool -delete -alias theAlias -keystore path/to/keystore –storepass pass
    • -printcert 控制台打印证书的详细信息,如:keytool -printcert -file path/to/keystore/cert -v
    • -keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias theAlias -keypass oldPass -new newPass -storepass keystorePass -keystore path/to/keystore
    • -storepasswd 修改keystore口令 keytool -storepasswd -keystore path/to/keystore -storepass oldPass -new newPass
    • -importcert 将已签名数字证书导入密钥库 keytool -importcert -alias certAlias -keystore path/to/keystore -file path/to/keystore/cert
  • 相关阅读:
    Angular 路由的参数传递
    Angular 指令的属性和事件绑定
    Angular 组件的双向绑定
    Angular 组件视图封装模式
    Angular 组件生命周期的顺序
    简谈 Angular 动态绑定样式的几种方法
    Angular 表单快速入门
    如何在 Angular CLI 创建的项目中自定义 webpack 配置
    bootstrap图标菜单按钮组件
    vue指令
  • 原文地址:https://www.cnblogs.com/zhangfengxian/p/java-CertPathValidatorException-algorithm-constraints-check-failed.html
Copyright © 2020-2023  润新知