You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java7集成BouncyCastle支持TLS1.3后SMTP发信证书错误解决方案

问题描述

应用当前运行在Java 1.7.0_79-b15版本环境下,由于对接的第三方应用将TLS版本升级至1.3,无法直接升级JDK版本获得原生TLS 1.3支持,因此引入Bouncy Castle组件满足对接要求。引入Bouncy Castle后已可正常连接第三方系统,但此前基于Java默认安全机制正常运行的邮件服务无法正常工作,报错信息如下:

Caused by: javax.mail.MessagingException: IOException while sending message;
  nested exception is:
    org.bouncycastle.tls.TlsFatalAlert: certificate_unknown(46)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:625)
    at javax.mail.Transport.send0(Transport.java:169)
    at javax.mail.Transport.send(Transport.java:98)
    at org.apache.commons.mail.Email.sendMimeMessage(Email.java:1232)
    ... 72 more
Caused by: org.bouncycastle.tls.TlsFatalAlert: certificate_unknown(46)
    at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.checkServerTrusted(Unknown Source)
    at org.bouncycastle.jsse.provider.ProvTlsClient$1.notifyServerCertificate(Unknown Source)
    at org.bouncycastle.tls.TlsUtils.processServerCertificate(Unknown Source)
    at org.bouncycastle.tls.TlsClientProtocol.handleServerCertificate(Unknown Source)
    at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
    at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
    at org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
    at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
    at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
    at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
    at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
    at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
    at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1301)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at java.net.URL.openStream(URL.java:1037)
    at javax.activation.URLDataSource.getInputStream(URLDataSource.java:107)
    at javax.activation.DataHandler.writeTo(DataHandler.java:304)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:845)
    at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:361)
    at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:85)
    at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:883)
    at javax.activation.DataHandler.writeTo(DataHandler.java:316)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:845)
    at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:361)
    at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:85)
    at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:883)
    at javax.activation.DataHandler.writeTo(DataHandler.java:316)
    at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1350)
    at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1683)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:585)
    ... 75 more
Caused by: java.security.cert.CertificateException: Unable to find certificate chain.
    at org.bouncycastle.jsse.provider.ProvX509TrustManager.validateChain(Unknown Source)
    at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkTrusted(Unknown Source)
    at org.bouncycastle.jsse.provider.ProvX509TrustManager.checkServerTrusted(Unknown Source)

核心诉求:通过SMTP发送邮件时是否可以禁用Bouncy Castle的证书校验流程?是否存在其他可行的问题修复方案?

解决方案

不建议全局禁用Bouncy Castle(以下简称BC)的证书校验,该操作会导致所有走BC的TLS连接失去服务端身份校验能力,存在极高的中间人攻击风险,生产环境绝对禁止使用。可按以下优先级选择修复方案:

  • 优先方案:隔离BC的使用范围,避免影响邮件服务
    报错的核心原因是注册BC安全提供者时将其放在了提供者列表的最高优先级,导致所有SSL/TLS连接(包括SMTP连接、邮件内嵌HTTPS资源拉取连接)都默认走BC的SSL实现,而BC默认的信任管理器不会加载JDK自带cacerts中的受信根证书,因此无法校验邮件服务器的证书链,抛出certificate_unknown错误。
    调整BC注册逻辑,不要使用Security.insertProviderAt(new BouncyCastleJsseProvider(), 1)这类将BC设置为最高优先级提供者的代码,仅在对接需要TLS 1.3的第三方服务时,单独为对应连接指定使用BC的SSLContext,其余业务(包括邮件服务)默认走JDK原生SunJSSE实现,二者完全隔离不会互相影响。
    针对JavaMail的SMTP连接,可显式配置参数强制使用JDK原生SSL提供者,不受全局安全配置影响:
    Properties props = new Properties();
    // SMTP非SSL端口使用STARTTLS时配置
    props.put("mail.smtp.ssl.provider", "com.sun.net.ssl.internal.ssl.Provider");
    // SMTPS直接SSL连接时配置
    props.put("mail.smtps.ssl.provider", "com.sun.net.ssl.internal.ssl.Provider");
    
  • 备选方案:为BC配置完整的信任根证书
    如果业务场景必须全局启用BC作为最高优先级SSL提供者,初始化BC的SSLContext时,手动将JDK默认cacerts信任库中的根证书、企业内部私有根证书导入BC的信任管理器,让BC可以正常校验包括邮件服务器在内的所有公网/内部服务证书链,从根源解决证书找不到的问题。
  • 测试环境临时方案:仅针对SMTP连接跳过证书校验
    如果仅需在测试环境临时验证邮件连通性,可单独为SMTP连接配置信任所有证书的规则,不要修改BC的全局校验逻辑:
    Properties props = new Properties();
    // 信任所有SMTP服务器证书
    props.put("mail.smtp.ssl.trust", "*");
    props.put("mail.smtps.ssl.trust", "*");
    

注意:上述跳过证书校验的配置仅可用于本地/测试环境,生产环境使用会导致邮件传输过程存在被窃听、篡改的风险。

内容的提问来源于stack exchange,提问作者Anthony Guillen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 13:51:29