1

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?

2Big2BeSmall
  • 1,348
  • 3
  • 20
  • 40
  • Why your connection string starts with `jdbc:mysql` but your exception is caused by `org.mariadb`? – pedrofb Nov 16 '17 at 16:46
  • 1
    Maria JDBC support my SQL license stuff – 2Big2BeSmall Nov 16 '17 at 16:47
  • You probably need to import amazonPublic.pem into a JKS or PKCS12 keystore. You can't use directly a .pem or .cer file with `javax.net.ssl.trustStore` – pedrofb Nov 16 '17 at 16:51
  • 1
    (1) I don't believe your file is a bare PUBLIC KEY; `CertificateFactory` can't read that. It can read PEM or DER certificates, or with `generateCertificates` (which you didn't use) a sequence or p7b. (2) Given a truststore containing the cert, `javax.net.ssl.trustStore*` are _system_ properties for JSSE, but the mariadb _driver_ properties are simply `trustStore` and `trustStorePassword` @pedrofb: mariadb is a fork of mysql and the mariadb driver supports both mysql and mariadb; posted code _does_ create a truststore. – dave_thompson_085 Nov 16 '17 at 18:08

1 Answers1

0

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());
2Big2BeSmall
  • 1,348
  • 3
  • 20
  • 40