We have a rest API written in SpringBoot using a 2-way ssl Auth.
We would like to send 401 HTTP status code when the user selects the wrong/expired client certificate.
When it happens I can see the exception:
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
The API starts normally and works fine. The exception occurs whenever the user tries to call my api selecting a wrong client certificate or invalid. In this case I would like to return 401 to the caller
Spring boot is configured with Tomcat and #EnableWebSecurity
http.x509().subjectPrincipalRegex("XXXXXX").userDetailsService(this.userDetailsService);
((RequiresChannelUrl)http.requiresChannel().anyRequest()).requiresSecure();
urls().forEach((url, guard) -> {
try {
((AuthorizedUrl)http.authorizeRequests().antMatchers(new String[]{url})).access(guard);
} catch (Exception var4) {
throw new UnsupportedOperationException("error");
}
});
Here the stack trace:
DirectJDKLog.java:175 [] Handshake failed during wrap
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
...
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 java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439)
....
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
The browser shows: ERR_BAD_SSL_CLIENT_AUTH_CERT
Is it possible to catch this exception in SpringBoot and send a specific HTTP status code?
Maybe you can try a controller advice:
#ControllerAdvice
class MyControllerExceptionHandler {
#ResponseStatus(HttpStatus.UNAUTHORIZED) // or whatever you want
#ExceptionHandler(SSLHandshakeException.class)
public void handleHandshakeException() {
// Nothing to do
}
}
Maybe the solution posted here or here can help you
In your security configuration you add this lines:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
//....
and().
.anonymous().disable()
.exceptionHandling()
.authenticationEntryPoint(new org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint("YourValue"));
}
and it will return HTTP 401:
Status Code: 401 Unauthorized
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Expires: 0
//... other header values
WWW-Authenticate: YourValue
Related
** ERROR SparkSubmit$$anon$2: Could not convert socket to TLS
javax.mail.MessagingException: Could not convert socket to TLS;
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.smtp.SMTPTransport.startTLS(SMTPTransport.java:2046)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:711)
at javax.mail.Service.connect(Service.java:366)
at javax.mail.Service.connect(Service.java:246)
at javax.mail.Service.connect(Service.java:195)
at javax.mail.Transport.send0(Transport.java:254)
passing this in config location :/javax.mail-1.5.5.jar ;: Is present in the lib location.
Code:
def sendEmail(fromAddr:String,toAddr:String,subjectLine: String,messageCont: String) ={
val emailProps = new Properties()
emailProps.put("mail.smtp.auth" , "false")
emailProps.put("mail.smtp.starttls.enable" , "true")
emailProps.put("mail.smtp.host" , "")
emailProps.put("mail.smtp.port" , "")
**
I am trying to get a JSON response back from an API call with a GET request. I know the server is protected and the application needs a certificate to be able to make a call.
Right now I have a certificate.pfx file which I can import in my browser and get responses back from the server.
How can I do this with my Java application so the application uses the certificate to connect to the server and get responses back?
package controllers;
import com.fasterxml.jackson.databind.JsonNode;
import models.UserProfile;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
import saleem.orm.utils.HibernateUtil;
import javax.net.ssl.HttpsURLConnection;
import javax.persistence.EntityManager;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class HomeController extends Controller {
public Result login() {
RequestJSON();
return ok(views.html.login.render());
}
public Result register() {
return ok(views.html.register.render());
}
public Result start() {
return ok(views.html.start.render());
}
public void RequestJSON() {
try {
// Censored the URL for the question
URL url = new URL("https://");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type", "application/json");
con.connect();
String res = con.getResponseMessage();
con.disconnect();
System.out.println(res);
} catch (IOException e) {
e.printStackTrace();
}
}
Stacktrace when my application tries to connect to the server:
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:198)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1967)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:331)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:325)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1689)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:226)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1082)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:1010)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1079)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1388)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1416)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1400)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:167)
at controllers.HomeController.RequestJSON(HomeController.java:56)
at controllers.HomeController.login(HomeController.java:24)
at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$2(Routes.scala:193)
at play.core.routing.HandlerInvokerFactory$$anon$6.resultCall(HandlerInvoker.scala:142)
at play.core.routing.HandlerInvokerFactory$$anon$6.resultCall(HandlerInvoker.scala:141)
at play.core.routing.HandlerInvokerFactory$JavaActionInvokerFactory$$anon$3$$anon$4$$anon$5.invocation(HandlerInvoker.scala:115)
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:119)
at play.http.DefaultActionCreator$1.call(DefaultActionCreator.java:33)
at play.core.j.JavaAction.$anonfun$apply$8(JavaAction.scala:175)
at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:672)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:431)
at play.core.j.HttpExecutionContext.$anonfun$execute$1(HttpExecutionContext.scala:64)
at play.api.libs.streams.Execution$trampoline$.execute(Execution.scala:70)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:59)
at scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:393)
at scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:302)
at scala.concurrent.impl.Promise$DefaultPromise.dispatchOrAddCallbacks(Promise.scala:276)
at scala.concurrent.impl.Promise$DefaultPromise.map(Promise.scala:146)
at scala.concurrent.Future$.apply(Future.scala:672)
at play.core.j.JavaAction.apply(JavaAction.scala:176)
at play.api.mvc.Action.$anonfun$apply$4(Action.scala:82)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture$4(Accumulator.scala:168)
at scala.util.Try$.apply(Try.scala:210)
at play.api.libs.streams.StrictAccumulator.$anonfun$mapFuture$3(Accumulator.scala:168)
at scala.Function1.$anonfun$andThen$1(Function1.scala:85)
at scala.Function1.$anonfun$andThen$1(Function1.scala:85)
at play.api.libs.streams.StrictAccumulator.run(Accumulator.scala:199)
at play.core.server.AkkaHttpServer.$anonfun$runAction$4(AkkaHttpServer.scala:417)
at akka.http.scaladsl.util.FastFuture$.strictTransform$1(FastFuture.scala:41)
at akka.http.scaladsl.util.FastFuture$.$anonfun$transformWith$3(FastFuture.scala:51)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:448)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:48)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:48)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
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:450)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:317)
at sun.security.validator.Validator.validate(Validator.java:262)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:227)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1671)
... 47 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:445)
... 53 more
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
As per the aforementioned exception, server identity is not getting validated by the client. The client has to validate the incoming server certificate during SSL handshake process and for that client rely on the root certificates (certificates used in signing the server certificate) present in the java truststore. Also, It's up to the client which truststore they want to use while making the connection.
Following is for adding the certificates for default java truststore i.e cacerts.
Locate the java truststore on your system. Usually, on windows os, it can be found at JAVA_HOME/jre/lib/security/cacerts. You can access this truststore using the default password changeit. Add the certificates into the store by using utilities such as keytool
This question already has answers here:
Resolving javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Error?
(33 answers)
Closed 5 years ago.
I would like to allow a connection from a java client.
This Java client needs to support multiple public keys for different DB's.
I must do it with a PUBLIC KEY and MUST NOT trust server certificate.
I have searched online but could not find a full solution for this problem, these are some of the links I have read:
first
second
third
I have also read this link myt question is not duplicate since its a completly different connection type - this is a JDBC connection with conneciton manager and not a general URL connection with SSL.
and many more, all the stack overflow solution I found offered to trust server certificate which means skip the public key verification
This is my code:
String connectionString = "jdbc:mysql://abcd-efg.rds.amazonaws.com:3306/test?trustServerCertificate=false&useSSL=true&requireSSL=true&verifyServerCertificate=true"
File f = new File("C:\\temp\\amazonPublic.pem");
CertificateFactory fact = null;
fact = CertificateFactory.getInstance("X.509");
X509Certificate cer = (X509Certificate) fact.generateCertificate(new FileInputStream(f));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
char[] password = new char[] {'1','2','3','4'};
ks.load(null, password);
ks.setCertificateEntry("alias", cer);
FileOutputStream fos = new FileOutputStream(new File("C:\\temp\\ca.cer"));
ks.store(fos, password);
fos.close();
Properties p = new Properties();
p.setProperty("javax.net.ssl.trustStore","C:\\temp\\ca.cer");
p.setProperty("javax.net.ssl.trustStorePassword","1234");
try (java.sql.Connection connection =
DriverManager.getConnection(connectionString,p)) {
connection.isValid(1000);
}
And this is the error:
Caused by: java.sql.SQLException: Could not connect to yyyyy-zz-prd-xxxxxxxxxxxx-1.rds.amazonaws.com:3306: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.handleConnectionPhases(AbstractConnectProtocol.java:706)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connect(AbstractConnectProtocol.java:406)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1022)
at org.mariadb.jdbc.internal.util.Utils.retrieveProxy(Utils.java:483)
at org.mariadb.jdbc.Driver.connect(Driver.java:106)
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:387)
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:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496)
... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 23 more
What am I missing in the solution?
For the sake of Humankind while working with MariaDB driver - debugging it
I find out that:
The property should be "serverSslCert" or "trustStore"
The prefix of javax.net.ssl only required when working with System.setProperty
So this simple change did the trick.
Properties p = new Properties();
p.setProperty("serverSslCert","C:/temp/amazonPublic.pem");
p.setProperty("trustStorePassword",jdbcDetails.getSensitiveData());
p.setProperty("user",jdbcDetails.username);
p.setProperty("password",jdbcDetails.getSensitiveData());
In Play 2.4.3 web app I need to call other service via HTTPS using WSClient. I followed the article but the error appears:
play.api.libs.ws.ssl.CompositeCertificateException: No trust manager
was able to validate this certificate chain: # of exceptions = 1
The exception inside CompositeCertificateException:
sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to
find valid certification path to requested target
Part of application.conf responsible for SSL:
play.ws.ssl {
trustManager = {
stores = [
{ type : "PEM", path : "C:/A/B/globalsign.crt" }
]
}
}
What's wrong here?
I solved the problem through the following steps:
Run InstallCert.java to generate jssecacerts file.
Add path to the file in application.conf.
Config example:
play.ws.ssl {
trustManager = {
stores = [
{path: "C:/A/B/jssecacerts"}
{path: ${java.home}/lib/security/cacerts}
]
}
}
I'm trying to write a test that will uses JavaMail SMTP or SMTPS to send a message via SSL and authentication to a Greenmail server that I'm running.
I've written a quick little sub that should do exactly what I'm wanting:
import java.util.Properties;
import javax.mail.Session;
import javax.mail.Transport;
import com.icegreen.greenmail.user.GreenMailUser;
import com.icegreen.greenmail.util.GreenMail;
public class MailTest {
public static void main(String[] args) throws Exception {
GreenMail greenmail = new GreenMail();
try {
greenmail.start();
String email = "foo#bar";
String userid = "user";
String password = "pa$$word";
GreenMailUser setUser = greenmail.setUser(email, userid, password);
setUser.create();
GreenMailUser user = greenmail.getManagers().getUserManager().getUser(userid);
System.out.println("User created:" + user.getEmail() + ":" + user.getLogin() + ":" + user.getPassword());
int portSmtps = greenmail.getSmtps().getPort();
System.out.println("Smtps started on port:" + portSmtps);
Properties props = new Properties();
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", "localhost");
props.put("mail.smtp.socketFactory.port", portSmtps);
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.fallback", "false");
Session session = Session.getInstance(props);
Transport transport = session.getTransport("smtp");
transport.connect("localhost", portSmtps, userid, password);
System.out.println("Transport is connected: " + transport.isConnected());
} finally {
greenmail.stop();
}
}
}
My problem is that I get several exceptions:
Exception in thread "Thread-7" java.lang.RuntimeException: javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
at com.icegreen.greenmail.smtp.SmtpHandler.run(Unknown Source)
Caused by: javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.java:1293)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:65)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at com.icegreen.greenmail.smtp.SmtpConnection.readLine(Unknown Source)
at com.icegreen.greenmail.smtp.SmtpHandler.handleCommand(Unknown Source)
... 1 more
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:632)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
at java.io.BufferedWriter.flush(BufferedWriter.java:236)
at java.io.PrintWriter.flush(PrintWriter.java:276)
at com.icegreen.greenmail.util.InternetPrintWriter.println(Unknown Source)
at com.icegreen.greenmail.util.InternetPrintWriter.println(Unknown Source)
at com.icegreen.greenmail.smtp.SmtpConnection.println(Unknown Source)
at com.icegreen.greenmail.smtp.SmtpHandler.sendGreetings(Unknown Source)
... 1 more
Exception in thread "main" javax.mail.MessagingException: Could not connect to SMTP host: localhost, port: 3465;
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.smtp.SMTPTransport.openServer(SMTPTransport.java:1934)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:638)
at javax.mail.Service.connect(Service.java:295)
at MailTest.main(MailTest.java:35)
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 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
at com.sun.mail.util.SocketFetcher.configureSSLSocket(SocketFetcher.java:507)
at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:238)
at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1900)
... 3 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:323)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
at sun.security.validator.Validator.validate(Validator.java:218)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:249)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1185)
... 13 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:174)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
... 19 more
I've tried looking at a few other answers here, but I must be missing something:
JavaMail to send secure email through vps - SSLHandshake Exception, PKIX path building failed, etc. - Can't send mail
PKIX path building failed: unable to find valid certification path to requested target
Using JavaMail with TLS
Sorry for the long post and thanks in advance for any advice.
You should start your GreenMail server like this:
Security.setProperty("ssl.SocketFactory.provider", DummySSLSocketFactory.class.getName());
GreenMail mailServer = new GreenMail(ServerSetupTest.SMTPS);
mailServer.start();
The SSL certificate used on the Greenmail server must be signed by a "known" certificate authority, OR you must add the CA certificate that was used to sign the cert to Java's keystore. There's no way to tell Java to not validate the certificate chain up to a known CA.
It also worked for me with JUNIT5:
#RegisterExtension
static GreenMailExtension greenMail = new GreenMailExtension(ServerSetupTest.POP3S.setVerbose(true));
#BeforeAll
static void setup() {
Security.setProperty("ssl.SocketFactory.provider", DummySSLSocketFactory.class.getName());
...
}