5

我正在尝试通过 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

我宁愿不使用 VM 参数,"-Djavax.net.ssl.trustStore"因为我希望能够控制每次访问的受信任证书。

旁注:我见过人们使用"mail.imap.socketFactory.class"SocketFactory定义的TrustManager. 但是当我这样做时,我的连接失败了

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

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

4

1 回答 1

5

我使用com.sun.mail:javax.mail:1.5.5从(不是那么标准的)pfx 文件加载的(根)证书来处理 SMTP 连接(不是 IMAP)。给定的属性以Session.getInstance(props)以下方式构建(另请参阅此处此处的 API 文档,我认为您可以简单地替换smtpimap大多数属性):

“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现在使用(阅读链接中的 API 文档) 构建一个 SSL 套接字工厂:
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)-方法)。请注意,已设置创建和配置的套接字工厂实例,而不是某个字符串或类。Javamail 将直接使用设置的套接字工厂实例。
使用属性创建会话。

确保您已正确配置日志并将其设置为 com.sun.mail 的 TRACE。日志记录准确显示了什么是“越界”,在我的例子中显示:
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

附带说明:可以使用此类SslUtils、方法loadKeyStore(null)createDefaultTrustStore()(我不久前创建了此实用程序类来帮助我加载不那么标准的 pfx 文件)来创建默认密钥库和信任库。

于 2016-01-13T18:04:39.693 回答