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

Using Java Mail StartTLS with a Truststore

我正在尝试通过 Java 邮件 API 连接到使用带有自签名证书的 StartTLS 的邮件服务器。 这似乎是个问题,因为我找不到任何方法来为 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 和从(不太标准的)pfx-file 加载的(根)证书为 SMTP 连接(不是 IMAP)工作。 Session.getInstance(props) 的属性按以下方式构建(另请参阅 API-docs here and here,我认为您可以简单地将 smtp 替换为 imap属性):

"mail.transport.protocol","smtp"
"mail.smtp.host","hostname"
"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"

现在使用 com.sun.mail.util.MailSSLSocketFactory 构建一个 SSL 套接字工厂(阅读 link 中的 API-docs):
MailSSLSocketFactory sslSocketFactory = new MailSSLSocketFactory("TLSv1.2");
创建并初始化(默认)KeyManagerFactory kmf(例如通过加载密钥库)。
创建并初始化一个(默认)TrustManagerFactory tmf
调用 sslSocketFactory.setKeyManagers(kmf.getKeyManagers())sslSocketFactory.setTrustManagers(tmf.getTrustManagers())
将 属性 "mail.smtp.ssl.socketFactory" 设置为 sslSocketFactory 实例(使用 props.put(k,v) 方法)。请注意,已设置创建和配置的套接字工厂实例,而不是某些 String 或 class。 Javamail 将直接使用设置的套接字工厂实例。
使用属性创建会话。

确保您已正确配置日志记录并将其设置为 com.sun.mail 的 TRACE。日志记录准确地显示了 "going over the line" 是什么,在我的例子中显示了例如:
DEBUG com.sun.mail.smtp - Found extension "STARTTLS", arg ""
...
TRACE com.sun.mail.smtp.protocol - STARTTLS
TRACE com.sun.mail.smtp.protocol - 220 Ready to start TLS

附带说明:可以使用 this SslUtils class、方法 loadKeyStore(null)createDefaultTrustStore() 创建默认密钥库和 trustore(我创建了这个实用程序 class前段时间帮我加载了not-so-standard pfx-files).