JavaMail 中的错误:PKIX 路径构建失败,无法找到所请求目标的有效认证路径
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20122099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Error in JavaMail : PKIX path building failed unable to find valid certification path to requested target
提问by fnkbz
I am trying to build an email client app in android and right now i want to configure the javaMail part.
我正在尝试在 android 中构建一个电子邮件客户端应用程序,现在我想配置 javaMail 部分。
i am trying to establish the connection with the imap server but something is wrong with my code.. here is my code:
我正在尝试与 imap 服务器建立连接,但我的代码有问题.. 这是我的代码:
package mailpackage;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
public class Connection implements Runnable
{
boolean done;
public Connection()
{
this.done=false;
}
@Override
public void run()
{
System.out.println("Hello from Connection Thread!");
while(!done)
{
String host = "myhost";// change accordingly
String mailStoreType = "imap";
String username = "myusername";// change accordingly
String password = "mypasswd";// change accordingly
check(host, mailStoreType, username, password);
}
}
public static void receiveEmail(String host, String storeType, String username, String password)
{
try
{
Properties properties = new Properties();
properties.put("mail.imap.com", host);
properties.put("mail.imap.starttls.enable","true");
properties.put("mail.imap.auth", "true"); // If you need to authenticate
// Use the following if you need SSL
properties.put("mail.imap.socketFactory.port", 993);
properties.put("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.put("mail.imap.socketFactory.fallback", "false");
Session emailSession = Session.getDefaultInstance(properties);
emailSession.setDebug(true);
//2) create the IMAP store object and connect with the Imap server
IMAPStore emailStore = (IMAPStore) emailSession.getStore(storeType);
emailStore.connect(host, username, password);
//3) create the folder object and open it
Folder emailFolder = emailStore.getFolder("INBOX");
emailFolder.open(Folder.READ_ONLY);
//4) retrieve the messages from the folder in an array and print it
Message[] messages = emailFolder.getMessages();
for (int i = 0; i <messages.length; i++)
{
Message message = messages[i];
MimeMessage m = new MimeMessage(emailSession);
m.setContent(((MimeMessage)messages[i]).getContent() , "text/plain; charset=UTF-8");
System.out.println("---------------------------------");
System.out.println("Email Number " + (i + 1));
System.out.println("Subject: " + message.getSubject());
System.out.println("From: " + message.getFrom()[0]);
System.out.println("Text: " + message.getContent().toString());
m.writeTo(System.out);
}
//5) close the store and folder objects
emailFolder.close(false);
emailStore.close();
}
catch (NoSuchProviderException e) {e.printStackTrace();}
catch (MessagingException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
}
public void stopThread()
{
this.done=true;
}
}
I call the thread from another class like this
我像这样从另一个班级调用线程
connec=new Connection();
(new Thread(connec)).start();
I get the Following errors:
我收到以下错误:
javax.mail.MessagingException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target;
nested exception is:
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
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:571)
at javax.mail.Service.connect(Service.java:288)
at javax.mail.Service.connect(Service.java:169)
at mailpackage.Connection.check(Connection.java:63)
at mailpackage.Connection.run(Connection.java:33)
at java.lang.Thread.run(Thread.java:744)
Caused by: 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
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:882)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
at com.sun.mail.util.TraceInputStream.read(TraceInputStream.java:110)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
at com.sun.mail.iap.ResponseInputStream.readResponse(ResponseInputStream.java:98)
at com.sun.mail.iap.Response.<init>(Response.java:96)
at com.sun.mail.imap.protocol.IMAPResponse.<init>(IMAPResponse.java:61)
at com.sun.mail.imap.protocol.IMAPResponse.readResponse(IMAPResponse.java:135)
at com.sun.mail.imap.protocol.IMAPProtocol.readResponse(IMAPProtocol.java:261)
at com.sun.mail.iap.Protocol.<init>(Protocol.java:114)
at com.sun.mail.imap.protocol.IMAPProtocol.<init>(IMAPProtocol.java:104)
at com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:538)
... 5 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
... 23 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
... 29 more
i read something about PKIX path error that says to add the cert to java store as a trusted cert, but i dont know if this is the solution for this, and if it is i dont know how to do it.
我读了一些关于 PKIX 路径错误的内容,说要将证书作为受信任的证书添加到 Java 存储中,但我不知道这是否是解决方案,如果是,我不知道该怎么做。
// i dont have access to the mail server
// 我无权访问邮件服务器
Any suggestions? thanks!
有什么建议?谢谢!
采纳答案by fnkbz
Ok problem solved!
好的问题解决了!
The solution is this:
解决办法是这样的:
First get the self-signed certificate from the mail server via openssl:
首先通过openssl从邮件服务器获取自签名证书:
echo | openssl s_client -connect yoursever:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > yourcert.pem
Then save the yourcert.pem file into this path /Library/Java/Home/lib/security (on macOSX) and put the cert file into the cacerts like this
然后将 yourcert.pem 文件保存到此路径 /Library/Java/Home/lib/security(在 macOSX 上)并将证书文件放入这样的 cacerts
keytool -keystore cacerts -importcert -alias youralias -file yourcert.pem
The default keystore password is changeit
默认的密钥库密码是 changeit
You can view the change that you made with this command that shows the Certificate fingerprint.
您可以查看使用此显示证书指纹的命令所做的更改。
keytool -list -keystore cacerts
keytool -list -keystore cacerts
After this you should pass these argument in VM
在此之后,您应该在 VM 中传递这些参数
(for windows and linux type yourpath between " " )
(对于 windows 和 linux,在 " " 之间输入你的路径)
-Djavax.net.ssl.trustStore="/Library/Java/Home/lib/security/cacerts"
-Djavax.net.ssl.trustStore="/Library/Java/Home/lib/security/cacerts"
-Djavax.net.ssl.trustStorePassword="changeit"
-Djavax.net.ssl.trustStorePassword="changeit"
For Debug:
对于调试:
-Djava.security.debug=certpath
-Djava.security.debug=certpath
-Djavax.net.debug=trustmanager
-Djavax.net.debug=trustmanager
回答by Bill Shannon
This JavaMail FAQ entry should help.
Quoted text from the linked site:
来自链接网站的引用文本:
Q: When connecting to my mail server over SSL I get an exception like "unable to find valid certification path to requested target".
A: Your server is probably using a test certificate or self-signed certificate instead of a certificate signed by a commercial Certificate Authority. You'll need to install the server's certificate into your trust store. The InstallCert program will help.
Alternatively, you can set the "mail.protocol.ssl.trust" property to the host name of your mail server. See the javadocs for the protocol provider packages for details.
Other common causes of this problem are:
- There's a firewall or anti-virus program intercepting your request.
- There's something wrong in your JDK installation preventing it from finding the certificates for the trusted certificate authorities.
- You're running in an application server that has overridden the JDK's list of trusted certificate authorities.
问:当通过 SSL 连接到我的邮件服务器时,我收到“无法找到到请求目标的有效认证路径”之类的异常。
答:您的服务器可能使用的是测试证书或自签名证书,而不是由商业证书颁发机构签署的证书。您需要将服务器的证书安装到您的信任库中。InstallCert 程序会有所帮助。
或者,您可以将“mail.protocol.ssl.trust”属性设置为邮件服务器的主机名。有关详细信息,请参阅协议提供程序包的 javadoc。
此问题的其他常见原因是:
- 有防火墙或防病毒程序在拦截您的请求。
- 您的 JDK 安装有问题,导致它无法找到受信任的证书颁发机构的证书。
- 您在已覆盖 JDK 的受信任证书颁发机构列表的应用程序服务器中运行。
回答by titojusto
I've lost so many days searching for a solution, and this post was helps to me. I had the same problem. I created a pem file like here, and then, the cert file .pem, was incrusted in cacert file (a copy called TrustStore.jks) with this command:
我已经失去了很多天寻找解决方案,这篇文章对我有帮助。我有同样的问题。我在这里创建了一个 pem 文件,然后使用以下命令将证书文件 .pem 嵌入 cacert 文件(名为 TrustStore.jks 的副本)中:
keytool.exe -import -noprompt -keystore TrustStore.jks -storepass changeit ^ -alias DOMAINNAME -file MYCERTFILE.pem
keytool.exe -import -noprompt -keystore TrustStore.jks -storepass changeit ^ -alias DOMAINNAME -file MYCERTFILE.pem
(DOMAINNAME must be replace by hostname -this trick is very important-, and MYCERTFILE by file recent create...)
(DOMAINNAME 必须由主机名替换 - 这个技巧非常重要 - 和 MYCERTFILE 由最近创建的文件...)
I hope that this solution can helps to somebody.
我希望这个解决方案可以对某人有所帮助。
回答by Brian Knoblauch
I also have run across this problem when talking to a mail server. However, the root cause was that the server (Exchange 2013) had both a real certificate AND a self-signed applied to it. The appropriate course of action was to remove the self-signed on the server because it was taking precedence and blocking the real certificate.
我在与邮件服务器交谈时也遇到过这个问题。但是,根本原因是服务器 (Exchange 2013) 同时应用了真实证书和自签名证书。适当的操作过程是删除服务器上的自签名,因为它优先并阻止真正的证书。
回答by Baji Shaik
easy way to solve this problem by getiing certificate file from Java 7
通过从 Java 7 获取证书文件来解决此问题的简单方法
copy the "cacerts" file from following java 7 directory
从以下 java 7 目录复制“cacerts”文件
C:\Program Files\Java\jdk1.7.0_79\jre\lib\security
and paste it in java 6 directory
并将其粘贴到 java 6 目录中
C:\Program Files\Java\jdk1.6.0\jre\lib\security
回答by TungHarry
You can try upgrade library javax.mail.jar at https://java.net/projects/javamail/pages/Home(now version is 1.5.5) and add code :
您可以尝试在https://java.net/projects/javamail/pages/Home(现在版本为 1.5.5)升级库 javax.mail.jar并添加代码:
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.imap.ssl.trust", "*");
properties.put("mail.imap.ssl.socketFactory", sf);