今天在项目中利用JAVAMAIL对自架的邮件服务器进行邮件发送,其中遇

  1. Caused by: javax.net.ssl.SSLHandshakeException:                 
  2.  sun.security.validator.ValidatorException: PKIX path building failed: 
  3. sun.security.provider.certpath.SunCertPathBuilderException:  
  4.     unable to find valid certification path to requested target 

 原来是自架的邮件服务器没有经过SSL验证,在JAVAMAIL Q&A 上已经有过说明

 http://www.oracle.com/technetwork/java/faq-135477.html#installcert

解决方法就是通过代码生成虚认证文件,将认证文件放入到JAVA_HOME/jre/lib/security/目录下,当运行程序时,JDK会根据认证文件获取邮件服务器的主机名、IP等信息(假设,实际运行原理等待考证)。

具体的操作步骤:http://kenai.com/projects/javamail/pages/InstallCert

另附上生成认证文件的代码,来自https://code.google.com/p/java-use-examples/source/browse/trunk/src/com/aw/ad/util/InstallCert.java

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