web-dev-qa-db-fra.com

Erreur dans JavaMail: la construction du chemin PKIX n'a ​​pas pu trouver le chemin de certification valide de la cible demandée

J'essaie de créer une application client de messagerie sous Android et je souhaite maintenant configurer la partie javaMail.

j'essaie d'établir la connexion avec le serveur imap mais quelque chose ne va pas avec mon code ... Voici mon code:

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;
    }
}

J'appelle le fil d'une autre classe comme celle-ci

connec=new Connection();
 (new Thread(connec)).start();

Je reçois les erreurs suivantes:

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

j'ai lu quelque chose à propos de l'erreur de chemin PKIX qui dit d'ajouter le cert au magasin Java en tant que cert de confiance, mais je ne sais pas si c'est la solution pour cela, et si c'est je ne sais pas comment le faire.

// je n'ai pas accès au serveur de messagerie

Aucune suggestion? Merci! 

21
fnkbz

Ok problème résolu!  

La solution est la suivante:

Commencez par obtenir le certificat auto-signé du serveur de messagerie via openssl:

echo | openssl s_client -connect yoursever:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > yourcert.pem

Enregistrez ensuite le fichier yourcert.pem dans le répertoire/Library/Java/Home/lib/security (sous macOSX) et placez le fichier de certificat dans le fichier cacerts comme ceci

keytool -keystore cacerts -importcert -alias youralias -file yourcert.pem

Le mot de passe du magasin de clés par défaut est changeit

Vous pouvez afficher les modifications que vous avez apportées avec cette commande qui affiche l'empreinte digitale du certificat.

keytool -list -keystore cacerts

Après cela, vous devriez passer cet argument dans VM

(pour windows et linux tapez yourpath entre "")

-Djavax.net.ssl.trustStore="/Library/Java/Home/lib/security/cacerts" 

-Djavax.net.ssl.trustStorePassword="changeit"

Pour le débogage:

-Djava.security.debug=certpath

-Djavax.net.debug=trustmanager

35
fnkbz

Vous pouvez essayer la bibliothèque de mise à niveau javax.mail.jar à l’adresse https://Java.net/projects/javamail/pages/Home (la version actuelle est 1.5.5) et ajouter le code suivant:

MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true); 
properties.put("mail.imap.ssl.trust", "*");
properties.put("mail.imap.ssl.socketFactory", sf);
21
TungHarry

moyen facile de résoudre ce problème en obtenant le fichier de certificat de Java 7

copier le fichier "cacerts" du répertoire Java 7 suivant

C:\Program Files\Java\jdk1.7.0_79\jre\lib\security

et collez-le dans le répertoire Java 6

C:\Program Files\Java\jdk1.6.0\jre\lib\security
2
Baji Shaik

Cette entrée JavaMail FAQ devrait vous aider.

Texte cité du site lié:

Q: Lors de la connexion à mon serveur de messagerie via SSL, une exception du type "impossible de trouver un chemin de certification valide pour la cible demandée".

R: Votre serveur utilise probablement un certificat de test ou un certificat auto-signé à la place d'un certificat signé par une autorité de certification commerciale. Vous devrez installer le certificat du serveur dans votre magasin de données de confiance. Le programme InstallCert vous aidera.

Vous pouvez également définir la propriété "mail.protocol.ssl.trust" sur le nom d'hôte de votre serveur de messagerie. Voir les javadocs pour les packages du fournisseur de protocole pour plus de détails.

Les autres causes courantes de ce problème sont:

  • Un pare-feu ou un programme antivirus intercepte votre demande.
  • Quelque chose ne va pas dans votre installation JDK l'empêchant de trouver les certificats pour les autorités de certification approuvées.
  • Vous utilisez un serveur d'applications qui a remplacé la liste d'autorités de certification approuvées du JDK.
1
Bill Shannon

J'ai également rencontré ce problème lorsque je parle à un serveur de messagerie. Cependant, la cause première était que le serveur (Exchange 2013) avait à la fois un certificat ET une signature auto-appliquée qui lui était appliquée. Le plan d’action approprié consistait à supprimer l’auto-signé sur le serveur car il prenait la priorité et bloquait le certificat réel.

0
Brian Knoblauch

Je devais remplacer:

props.setProperty("mail.smtp.starttls.enable", "true");
props.setProperty("mail.smtp.auth", "true");

avec:

props.put("mail.smtp.starttls.enable", true);
props.put("mail.smtp.auth", true);

se débarrasser de l'erreur.

Notez que j'utilise jetty 9, qui inclut une ancienne version de javamail.

J'ai posté ceci parce que l'erreur ne doit pas signifier qu'il y a quelque chose qui ne va pas avec le certificat.

0
Tinus Tate

J'ai perdu tellement de jours à chercher une solution, et cet article m'aidait beaucoup. J'ai eu le même problème. J'ai créé un fichier pem comme ici, puis le fichier de certificat .pem a été incrusté dans un fichier cacert (une copie appelée TrustStore.jks) avec cette commande:

keytool.exe -import -noprompt -keystore TrustStore.jks -storepass changeit ^ -alias DOMAINNAME-fichier MYCERTFILE.pem

(DOMAINNAME doit être remplacé par nom d'hôte -cette astuce est très importante-, et MYCERTFILE par le fichier recent create ...)

J'espère que cette solution peut aider quelqu'un.

0
titojusto