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

来源:互联网 发布:python递归函数怎么写 编辑:程序博客网 时间:2024/05/22 07:49

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

PKIX:nable to find valid certification path to requested target

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

原文地址: 

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?在CODE上查看代码片派生到我的代码片
  1. Protocol    Store or    Uses    Supports  
  2. Name        Transport?  SSL?    STARTTLS?  
  3. -------------------------------------------------  
  4. imap        Store       No      Yes  
  5. imaps       Store       Yes     N/A  
  6. pop3        Store       No      Yes  
  7. pop3s       Store       Yes     N/A  
  8. smtp        Transport   No      Yes  
  9. smtps       Transport   Yes     N/A  
Transport使用SSL连接邮箱协议名称需要使用smtps,而不是smtp,参数需做如下修改:

[java] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. public class JavaMailTest1 {  
  2.     public static void main(String[] args) throws MessagingException {  
  3.         Properties props = new Properties();  
  4.         props.setProperty("mail.debug""true");  
  5.         props.setProperty("mail.smtp.auth""true");  
  6.         // props.setProperty("mail.transport.protocol""smtps");  加这句
  7.           
  8.         // SSL  
  9.         props.setProperty("mail.smtp.socketFactory.class""javax.net.ssl.SSLSocketFactory");  
  10.         props.setProperty("mail.smtp.socketFactory.fallback""false");  
  11.         props.setProperty("mail.smtp.port""465");  
  12.         props.setProperty("mail.smtp.socketFactory.port""465"); 
  13.         props.setProperty("mail.smtp.ssl.enable""true");  //或者加这句 都能用ssl发
  14.           
  15.         Session session = Session.getInstance(props);  
  16.           
  17.         Message msg = new MimeMessage(session);  
  18.         msg.setText("你好吗?");  
  19.         msg.setFrom(new InternetAddress("发件箱地址"));  
  20.           
  21.         Transport transport = session.getTransport();  
  22.         transport.connect("smtp.sina.com""用户名""密码");  
  23.         transport.sendMessage(msg, new Address[] {new InternetAddress("收件箱地址")});  
  24.         transport.close();  
  25.     }  
  26. }  

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

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

0 0
原创粉丝点击