Could not connect to SMTP host,PKIX path building failed,unable to find valid certification path...

系统管理员 2022-07-20 12:30 346阅读 0赞

java发邮件时遇到的问题

公司最近将邮件系统进行了升级,升级之后的邮件必须采用邮件加密传输通道。也就是ssl登录。

之前写的普通登录也将无法使用。今天在修改程序的过程中出现了一些问题,最终都顺利解决了,记录一下。

登录方式

普通登录

  1. <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
  2. <property name="host" value="${mail.smtp.host}" />
  3. <property name="javaMailProperties">
  4. <props>
  5. <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
  6. <prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop>
  7. </props>
  8. </property>
  9. <property name="username" value="${mail.smtp.username}" />
  10. <property name="password" value="${mail.smtp.password}" />
  11. </bean>

ssl登录

  1. <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
  2. <property name="host" value="${mail.smtp.host}" />
  3. <property name="port" value="${mail.smtp.port}" />
  4. <property name="username" value="${mail.smtp.username}" />
  5. <property name="password" value="${mail.smtp.password}" />
  6. <property name="javaMailProperties">
  7. <props>
  8. <prop key="mail.smtp.timeout">${mail.smtp.timeout}</prop>
  9. <prop key="mail.smtp.auth">${mail.smtp.auth}</prop>
  10. <prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
  11. <prop key="mail.smtp.socketFactory.port">${mail.smtp.port}</prop>
  12. <prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
  13. <prop key="mail.smtp.socketFactory.fallback">false</prop>
  14. </props>
  15. </property>
  16. </bean>

配置文件

  1. #------------------------------------------------------------------------------------
  2. # 邮件服务的配置
  3. #------------------------------------------------------------------------------------
  4. #服务器
  5. mail.smtp.host=smtp.abc.com
  6. #端口号,QQ邮箱需要使用SSL,端口号465或587,其他邮箱默认的端口号:25
  7. mail.smtp.port=465
  8. #STARTTLS是对纯文本通信协议的扩展。它提供一种方式将纯文本连接升级为加密连接(TLS或SSL)
  9. mail.smtp.starttls.enable=true
  10. #是否需要验证密码
  11. mail.smtp.auth=true
  12. #超时时间
  13. mail.smtp.timeout=50000
  14. #------------------------------------------------------------------------------------
  15. # 加解密密钥 不能给出
  16. # 对用户名和密码都进行了加密 加解密工具在DESUtil中
  17. #------------------------------------------------------------------------------------
  18. #登陆用户名 我是随便写的
  19. mail.smtp.username=CBoch2LlydMW2432VYReDe4tjvJRstAmCoE123111
  20. #密码 qq为授权码 111111我是随便写的
  21. mail.smtp.password=avq5JeBiMuNr5F4wclLZZA==

改为ssl后遇到的问题

  1. Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: smtp.abc.com, port: 465;
  2. nested exception is:
  3. 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. Failed messages: javax.mail.MessagingException: Could not connect to SMTP host: smtp.abc.com, port: 465;
  4. nested exception is:
  5. 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

错误为:

  1. Could not connect to SMTP host: smtp.abc.com, port: 465
  2. PKIX path building failed
  3. unable to find valid certification path to requested target

其中1和2是由3引起的

现在问题就是解决

  1. unable to find valid certification path to requested target

网上有两种解决方案

1 安装数字证书
2 生成证书

我把公司的数字证书安装后没有解决问题,采用第二种方法解决

参考文献
http://www.tuicool.com/articles/zUjiIb

其中这篇文章中有一个地方在邮件系统中需要注意
url需要加上端口号

这里写图片描述

看到如下信息表示成功地生成了证书

这里写图片描述

将生成的jssecacerts文件拷贝到%JAVA_HONME%\jre\lib\security\目录下就ok了。

这里写图片描述

附上InstallCert.java

  1. /* * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Sun Microsystems nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.io.InputStream;
  7. import java.io.InputStreamReader;
  8. import java.io.OutputStream;
  9. import java.security.KeyStore;
  10. import java.security.MessageDigest;
  11. import java.security.cert.CertificateException;
  12. import java.security.cert.X509Certificate;
  13. import javax.net.ssl.SSLContext;
  14. import javax.net.ssl.SSLException;
  15. import javax.net.ssl.SSLSocket;
  16. import javax.net.ssl.SSLSocketFactory;
  17. import javax.net.ssl.TrustManager;
  18. import javax.net.ssl.TrustManagerFactory;
  19. import javax.net.ssl.X509TrustManager;
  20. public class InstallCert {
  21. public static void main(String[] args) throws Exception {
  22. String host;
  23. int port;
  24. char[] passphrase;
  25. if ((args.length == 1) || (args.length == 2)) {
  26. String[] c = args[0].split(":");
  27. host = c[0];
  28. port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
  29. String p = (args.length == 1) ? "changeit" : args[1];
  30. passphrase = p.toCharArray();
  31. } else {
  32. System.out
  33. .println("Usage: java InstallCert <host>[:port] [passphrase]");
  34. return;
  35. }
  36. File file = new File("jssecacerts");
  37. if (file.isFile() == false) {
  38. char SEP = File.separatorChar;
  39. File dir = new File(System.getProperty("java.home") + SEP + "lib"
  40. + SEP + "security");
  41. file = new File(dir, "jssecacerts");
  42. if (file.isFile() == false) {
  43. file = new File(dir, "cacerts");
  44. }
  45. }
  46. System.out.println("Loading KeyStore " + file + "...");
  47. InputStream in = new FileInputStream(file);
  48. KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
  49. ks.load(in, passphrase);
  50. in.close();
  51. SSLContext context = SSLContext.getInstance("TLS");
  52. TrustManagerFactory tmf = TrustManagerFactory
  53. .getInstance(TrustManagerFactory.getDefaultAlgorithm());
  54. tmf.init(ks);
  55. X509TrustManager defaultTrustManager = (X509TrustManager) tmf
  56. .getTrustManagers()[0];
  57. SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
  58. context.init(null, new TrustManager[] { tm }, null);
  59. SSLSocketFactory factory = context.getSocketFactory();
  60. System.out
  61. .println("Opening connection to " + host + ":" + port + "...");
  62. SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
  63. socket.setSoTimeout(10000);
  64. try {
  65. System.out.println("Starting SSL handshake...");
  66. socket.startHandshake();
  67. socket.close();
  68. System.out.println();
  69. System.out.println("No errors, certificate is already trusted");
  70. } catch (SSLException e) {
  71. System.out.println();
  72. e.printStackTrace(System.out);
  73. }
  74. X509Certificate[] chain = tm.chain;
  75. if (chain == null) {
  76. System.out.println("Could not obtain server certificate chain");
  77. return;
  78. }
  79. BufferedReader reader = new BufferedReader(new InputStreamReader(
  80. System.in));
  81. System.out.println();
  82. System.out.println("Server sent " + chain.length + " certificate(s):");
  83. System.out.println();
  84. MessageDigest sha1 = MessageDigest.getInstance("SHA1");
  85. MessageDigest md5 = MessageDigest.getInstance("MD5");
  86. for (int i = 0; i < chain.length; i++) {
  87. X509Certificate cert = chain[i];
  88. System.out.println(" " + (i + 1) + " Subject "
  89. + cert.getSubjectDN());
  90. System.out.println(" Issuer " + cert.getIssuerDN());
  91. sha1.update(cert.getEncoded());
  92. System.out.println(" sha1 " + toHexString(sha1.digest()));
  93. md5.update(cert.getEncoded());
  94. System.out.println(" md5 " + toHexString(md5.digest()));
  95. System.out.println();
  96. }
  97. System.out
  98. .println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
  99. String line = reader.readLine().trim();
  100. int k;
  101. try {
  102. k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
  103. } catch (NumberFormatException e) {
  104. System.out.println("KeyStore not changed");
  105. return;
  106. }
  107. X509Certificate cert = chain[k];
  108. String alias = host + "-" + (k + 1);
  109. ks.setCertificateEntry(alias, cert);
  110. OutputStream out = new FileOutputStream("jssecacerts");
  111. ks.store(out, passphrase);
  112. out.close();
  113. System.out.println();
  114. System.out.println(cert);
  115. System.out.println();
  116. System.out
  117. .println("Added certificate to keystore 'jssecacerts' using alias '"
  118. + alias + "'");
  119. }
  120. private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
  121. private static String toHexString(byte[] bytes) {
  122. StringBuilder sb = new StringBuilder(bytes.length * 3);
  123. for (int b : bytes) {
  124. b &= 0xff;
  125. sb.append(HEXDIGITS[b >> 4]);
  126. sb.append(HEXDIGITS[b & 15]);
  127. sb.append(' ');
  128. }
  129. return sb.toString();
  130. }
  131. private static class SavingTrustManager implements X509TrustManager {
  132. private final X509TrustManager tm;
  133. private X509Certificate[] chain;
  134. SavingTrustManager(X509TrustManager tm) {
  135. this.tm = tm;
  136. }
  137. public X509Certificate[] getAcceptedIssuers() {
  138. throw new UnsupportedOperationException();
  139. }
  140. public void checkClientTrusted(X509Certificate[] chain, String authType)
  141. throws CertificateException {
  142. throw new UnsupportedOperationException();
  143. }
  144. public void checkServerTrusted(X509Certificate[] chain, String authType)
  145. throws CertificateException {
  146. this.chain = chain;
  147. tm.checkServerTrusted(chain, authType);
  148. }
  149. }
  150. }

注意

不能将在自己电脑上生成的jssecacerts文件拷贝到服务器上去,如果拷贝上去不会起作用,仍然会报错。
服务器必须编译InstallCert.java,去生成jssecacerts文件。

参考文献

1.解决PKIX问题:unable to find valid certification path to requested target

2.Java发邮件-QQ服务器认证(A secure connection is requiered(such as ssl))

发表评论

表情:
评论列表 (有 0 条评论,346人围观)

还没有评论,来说两句吧...

相关阅读