zoukankan      html  css  js  c++  java
  • java与Sql Server建立连接异常Could not generate DH keypair及Unsupported curveId: 29

    前言

    最近在工作中想完成一个java通过jdbc连接SQL Server数据库导出数据字典的功能时发现本地用jdk8和对应的SQL Server驱动(可通过SQLServer官网或者maven库下载-mssql-jdbc-8.2.2.jre8.jar)可以正常连接SQL Server2019,然后当我们导出jar包到项目中打算使用时,发现项目的环境是jdk1.6,这时程序与SQL Server2019无法正常建立连接,因为驱动是要在jre8的环境下才能运行的。这时我们就想换成jdk1.6支持的SQL Server驱动——sqljdbc4.jar,本以为换个驱动即可正常运行,结果发现接下来引发的异常竟让我折腾了一整天。

    问题原因

    jdk1.6因为安全套接字加密协议的不同,当连接SQL Server2014及以上版本时需要额外的jar包(bcpkix-jdk15on-1.60.jarbcprov-ext-jdk15on-1.60.jar)和修改java.security(jdk目录下的/jre/lib/security/java.security)使其能成功使用我们引入的包

    解决过程

    开始时,直接换了jar包后连接本地的SQL Server2019直接报异常:

    com.microsoft.sqlserver.jdbc.SQLServerException: 驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“java.lang.RuntimeException: Could not generate DH keypair”。
    	at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1352)
    	at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1533)
    	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1042)
    	at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:817)
    	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:700)
    	at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:842)
    	at java.sql.DriverManager.getConnection(DriverManager.java:582)
    	at java.sql.DriverManager.getConnection(DriverManager.java:185)
    Caused by: javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
    	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)
    	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1747)
    	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1708)
    	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1691)
    	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1222)
    	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199)
    	at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1483)

    我在网上各种搜索发现大家都建议升级到jdk7+版本来解决,虽然这样一劳永逸,但是由于生产环境用的是1.6版本并不能轻易升级(很无奈,怪系统太旧了。。。),或者是使用低版本的SQL Server(2012版本或更低版本),但是博主希望的是在1.6版本下且所有SQL Server版本都能使用(还不是因为生产是1.6哇!orz)。由此开始了解决版本问题的漫漫长路。

    1. 下载上述列出的两个包后放入到jdk目录下jrelibext

    2. 修改jrelibsecurityjava.security:

    找到“List of providers and their preference orders (see above):”下的security.provider信息,将
        security.provider.3=com.sun.net.ssl.internal.ssl.Provider
    用#号进行注释并用以下代码进行替换(security.provider后有下划线的数字最好也按你们文件原有顺序排列下去)
        security.provider.3=net.tobszarny.ssl.java6.provider.BouncyCastleSSLProvider
        security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider

    #
    # List of providers and their preference orders (see above):
    #
    security.provider.1=sun.security.provider.Sun
    security.provider.2=sun.security.rsa.SunRsaSign
    #注释了下面这行,并重新添加
    #security.provider.3=com.sun.net.ssl.internal.ssl.Provider
    #试着奔跑的菜鸟添加的下面这行
    security.provider.3=net.tobszarny.ssl.java6.provider.BouncyCastleSSLProvider
    security.provider.4=com.sun.crypto.provider.SunJCE
    security.provider.5=sun.security.jgss.SunProvider
    security.provider.6=com.sun.security.sasl.Provider
    security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI
    security.provider.8=sun.security.smartcardio.SunPCSC
    security.provider.9=sun.security.mscapi.SunMSCAPI
    #试着奔跑的菜鸟添加的下面这行
    security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider

    注意事项

    在我搜索的方法中,有些人说是直接在原security.provider的末尾加上那两行代码即可,但是博主不行,一直报错(Unsupported curveId: 29)而必须将原有的ssl.Provider注释后替换那两行代码才能成功运行。博主猜测的是如果没有注释掉的话,安全套接字加密就用了原有的类而不是使用我们导入的jar包中的类了,但是暂不能保证是否会对其他安全套接字加密的功能有所影响。

    最后再重新连接SQLServer即可,当然如果启动了服务器也要将服务器重启后再重试。

    结语及反思

    这次解决问题花费的时间很长,主要是一开始卡在找两个jar包的路上,因为在搜索引擎上搜到很多其他csdn的博客给出的jar都是需要积分下载的,很多下载后还货不对板 - _-|||,后来才发现Maven库这个东西,找对应版本的jar包简直不要太方便(在这里也不得不吐槽博主在csdn提供出去下载的东西还不能设置免积分)。
    当然也希望以后做的都能用jdk8+,不然解决年代久远的环境问题可太累了。

    才疏学浅,如文中有错误,感谢大家指出。

  • 相关阅读:
    Java NIO(六)选择器
    Java NIO(五)套接字通道
    Java NIO(四)文件通道
    Java NIO(三)通道
    Java NIO(二)缓冲区
    Java NIO(一)概述
    gcc中的内嵌汇编语言(Intel i386平台)
    一些汇编指令
    403 Forbidden解决方案
    Linux从入门到放弃
  • 原文地址:https://www.cnblogs.com/runningRookie/p/14348227.html
Copyright © 2011-2022 走看看