将Java Mail StartTLS与信任库一起使用

将Java Mail StartTLS与信任库一起使用,java,jakarta-mail,starttls,Java,Jakarta Mail,Starttls,我正在尝试连接到一个邮件服务器,该服务器使用StartTLS,并通过javamailapi使用自签名证书。 这似乎是个问题,因为我找不到任何方法来为StartTLS设置可接受的证书或信任库 Properties props = new Properties(); props.put("mail.imap.starttls.enable", "true"); props.put("mail.imap.starttls.required", "true"); Session session = Se

我正在尝试连接到一个邮件服务器,该服务器使用StartTLS,并通过javamailapi使用自签名证书。 这似乎是个问题,因为我找不到任何方法来为StartTLS设置可接受的证书或信任库

Properties props = new Properties();
props.put("mail.imap.starttls.enable", "true");
props.put("mail.imap.starttls.required", "true");
Session session = Session.getInstance(props);
Store store = session.getStore("imap");
store.connect(hostName, port, userName, userPassword);
当我按原样运行应用程序时,会出现以下PKIX路径错误:

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
我不希望使用像
“-Djavax.net.ssl.trustStore”
这样的VM参数,因为我希望能够控制每次访问的受信任证书

旁注:我见过人们使用
“mail.imap.socketFactory.class”
设置自己的
socketFactory
实现,并使用自定义的
TrustManager
。 但是当我这样做的时候,我的连接就失败了

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

我认为这是因为设置套接字工厂实际上将使用SSL上的SMTP,而不是StartTLS(它以纯文本连接开始,稍后切换到TLS)。

我使用
com.sun.mail:javax.mail:1.5.5
和从(非标准)加载的(root)证书为SMTP连接(而非IMAP)实现了这一点pfx文件。提供给
Session.getInstance(props)
的属性是以以下方式构建的(另请参见API文档,我认为对于大多数属性,您可以简单地将
smtp
替换为
imap
):

“邮件.传输.协议”,“smtp”
“mail.smtp.host”、“主机名”
“mail.smtp.port”“25”
“mail.smtp.connecttimeout”,“5000”//5秒
“mail.smtp.timeout”,“50000”//50秒
“mail.smtp.ssl.protocols”、“TLSv1.2”
mail.smtp.starttls.required”、“true”

现在使用(阅读链接中的API文档)构建SSL套接字工厂:
mailssocketfactory-sslSocketFactory=新的mailssocketfactory(“TLSv1.2”)

创建并初始化(默认)
KeyManagerFactory kmf
(例如,通过加载密钥库)。
创建并初始化(默认)
TrustManagerFactoryTMF

调用
sslSocketFactory.setKeyManagers(kmf.getKeyManagers())
sslSocketFactory.setTrustManagers(tmf.getTrustManagers())

将属性“mail.smtp.ssl.socketFactory”设置为
sslSocketFactory
实例(使用
props.put(k,v)
-method)。请注意,已创建和配置的套接字工厂实例已设置,而不是某些字符串或类。Javamail将直接使用set套接字工厂实例。
使用属性创建会话

确保已正确配置日志记录,并将其设置为com.sun.mail的跟踪。日志准确地显示了什么是“越界”,在我的例子中显示了:
DEBUG com.sun.mail.smtp-找到扩展名“STARTTLS”,arg”“

。。。
TRACE com.sun.mail.smtp.protocol-STARTTLS

TRACE com.sun.mail.smtp.protocol-220准备启动TLS


另一方面:可以使用类、方法
loadKeyStore(null)
createDefaultTrustStore()
创建默认密钥库和信任库(我不久前创建了这个实用程序类,以帮助我加载不太标准的pfx文件)。

除上述方法外,只需将属性设置为您想要信任的主机的名称,就可以简化这一过程。或者,您可以使用该程序将自签名证书从服务器加载到默认的信任存储中。我使用的是Java mail的1.3版本,必须升级才能获得MailSSLSocketFactory。工作起来很有魅力。