JavaMail使用SSL遇到安全证书问题

    xiaoxiao2021-03-25  95

    业务需求又发生的改变,登录模块中要用邮箱去验证,于是试试企业邮件服务器发邮件,结果使用SSL遇到

    PKIX:nable to find valid certification path to requested target

    通过搜索和查询资料发现上一篇文章给出了一个关键性的步骤-获取安全证书。

    原文地址: 

    http://blog.csdn.net/faye0412/article/details/6883879

    获取安全证书的代码收藏下来:

    import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.security.KeyStore; import java.security.MessageDigest; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; public class InstallCert {     public static void main(String[] args) throws Exception {         String host;         int port;         char[] passphrase;         if ((args.length == 1) || (args.length == 2)) {             String[] c = args[0].split(":");             host = c[0];             port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);             String p = (args.length == 1) ? "changeit" : args[1];             passphrase = p.toCharArray();         } else {             System.out                     .println("Usage: java InstallCert <host>[:port] [passphrase]");             return;         }         File file = new File("jssecacerts");         if (file.isFile() == false) {             char SEP = File.separatorChar;             File dir = new File(System.getProperty("java.home") + SEP + "lib"                     + SEP + "security");             file = new File(dir, "jssecacerts");             if (file.isFile() == false) {                 file = new File(dir, "cacerts");             }         }         System.out.println("Loading KeyStore " + file + "...");         InputStream in = new FileInputStream(file);         KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());         ks.load(in, passphrase);         in.close();         SSLContext context = SSLContext.getInstance("TLS");         TrustManagerFactory tmf = TrustManagerFactory                 .getInstance(TrustManagerFactory.getDefaultAlgorithm());         tmf.init(ks);         X509TrustManager defaultTrustManager = (X509TrustManager) tmf                 .getTrustManagers()[0];         SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);         context.init(null, new TrustManager[] { tm }, null);         SSLSocketFactory factory = context.getSocketFactory();         System.out                 .println("Opening connection to " + host + ":" + port + "...");         SSLSocket socket = (SSLSocket) factory.createSocket(host, port);         socket.setSoTimeout(10000);         try {             System.out.println("Starting SSL handshake...");             socket.startHandshake();             socket.close();             System.out.println();             System.out.println("No errors, certificate is already trusted");         } catch (SSLException e) {             System.out.println();             e.printStackTrace(System.out);         }         X509Certificate[] chain = tm.chain;         if (chain == null) {             System.out.println("Could not obtain server certificate chain");             return;         }         BufferedReader reader = new BufferedReader(new InputStreamReader(                 System.in));         System.out.println();         System.out.println("Server sent " + chain.length + " certificate(s):");         System.out.println();         MessageDigest sha1 = MessageDigest.getInstance("SHA1");         MessageDigest md5 = MessageDigest.getInstance("MD5");         for (int i = 0; i < chain.length; i++) {             X509Certificate cert = chain[i];             System.out.println(" " + (i + 1) + " Subject "                     + cert.getSubjectDN());             System.out.println("   Issuer  " + cert.getIssuerDN());             sha1.update(cert.getEncoded());             System.out.println("   sha1    " + toHexString(sha1.digest()));             md5.update(cert.getEncoded());             System.out.println("   md5     " + toHexString(md5.digest()));             System.out.println();         }         System.out                 .println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");         String line = reader.readLine().trim();         int k;         try {             k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;         } catch (NumberFormatException e) {             System.out.println("KeyStore not changed");             return;         }         X509Certificate cert = chain[k];         String alias = host + "-" + (k + 1);         ks.setCertificateEntry(alias, cert);         OutputStream out = new FileOutputStream("jssecacerts");         ks.store(out, passphrase);         out.close();         System.out.println();         System.out.println(cert);         System.out.println();         System.out                 .println("Added certificate to keystore 'jssecacerts' using alias '"                         + alias + "'");     }     private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();     private static String toHexString(byte[] bytes) {         StringBuilder sb = new StringBuilder(bytes.length * 3);         for (int b : bytes) {             b &= 0xff;             sb.append(HEXDIGITS[b >> 4]);             sb.append(HEXDIGITS[b & 15]);             sb.append(' ');         }         return sb.toString();     }     private static class SavingTrustManager implements X509TrustManager {         private final X509TrustManager tm;         private X509Certificate[] chain;         SavingTrustManager(X509TrustManager tm) {             this.tm = tm;         }         public X509Certificate[] getAcceptedIssuers() {             return new X509Certificate[0];            // throw new UnsupportedOperationException();         }         public void checkClientTrusted(X509Certificate[] chain, String authType)                 throws CertificateException {             throw new UnsupportedOperationException();         }         public void checkServerTrusted(X509Certificate[] chain, String authType)                 throws CertificateException {             this.chain = chain;             tm.checkServerTrusted(chain, authType);         }     } }

    生成证书的方法:

    1.编译InstallCert.java

    2.执行java InstallCert host password

    例如:java InstalCert smtp.zhangsan.com:465 admin

    如果不加参数password和host的端口号,上面的获取证书程序中默认给的端口号是:443,密码是:changeit

    3.根据运行提示信息,输入1,回车,在当前目录下生成名为: jssecacerts 的证书

    4.重要:

    将证书放置到$JAVA_HOME/jre/lib/security目录下, 切记该JDK的jre是工程所用的环境!!!

       5、以后更新时,先删除原来的证书,然后倒入新证书

        keytool -list -keystore cacerts -- 查看证书列表

        keytool -delete -alias akazam_email -keystore cacerts

        keytool -import -alias akazam_email -file akazam_email.cer -keystore cacerts -trustcacerts 

    6、今天无意中看到了javaMail有这样的协议支持描述:

    [plain]  view plain  copy  print ? Protocol    Store or    Uses    Supports   Name        Transport?  SSL?    STARTTLS?   -------------------------------------------------   imap        Store       No      Yes   imaps       Store       Yes     N/A   pop3        Store       No      Yes   pop3s       Store       Yes     N/A   smtp        Transport   No      Yes   smtps       Transport   Yes     N/A   Transport使用SSL连接邮箱协议名称需要使用smtps,而不是smtp,参数需做如下修改:

    [java]  view plain  copy  print ? public class JavaMailTest1 {       public static void main(String[] args) throws MessagingException {           Properties props = new Properties();           props.setProperty("mail.debug""true");           props.setProperty("mail.smtp.auth""true");           // props.setProperty("mail.transport.protocol""smtps");  加这句                    // SSL           props.setProperty("mail.smtp.socketFactory.class""javax.net.ssl.SSLSocketFactory");           props.setProperty("mail.smtp.socketFactory.fallback""false");           props.setProperty("mail.smtp.port""465");           props.setProperty("mail.smtp.socketFactory.port""465");          props.setProperty("mail.smtp.ssl.enable""true");  //或者加这句 都能用ssl发                    Session session = Session.getInstance(props);                      Message msg = new MimeMessage(session);           msg.setText("你好吗?");           msg.setFrom(new InternetAddress("发件箱地址"));                      Transport transport = session.getTransport();           transport.connect("smtp.sina.com""用户名""密码");           transport.sendMessage(msg, new Address[] {new InternetAddress("收件箱地址")});           transport.close();       }   }  

      这样,JavaMail会自动使用SSL,并且使用465端口。

    类似问题还可以参考:http://blog.csdn.net/pingyan158/article/details/60961515

    转载请注明原文地址: https://ju.6miu.com/read-12700.html

    最新回复(0)