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