1

I'm having trouble with my java truststore. I would be very grateful if someone could help me with this problem. I've built a micro service with Spring-Boot for geocoding in which I want to use the Google Geocoding API. Unfortunately, I'm getting a SSL Handshake Exception, despite the fact that I've downloaded the Google Authority G3 certificate via Open SSL, imported it into a new truststore file, and included this truststore file into my code.

Edit: This is the precise error message I'm getting:

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 targe

Here is my code:

The truststore entry in my application properties:

server.ssl.trust-store=src\\main\\java\\de\\projectname\\microservicename\\geographical\\files\\newTrustStore

server.ssl.trust-store-password=changeit

Edit2:

This is the keytool command I used to import the Google certificate in my truststore and save it in my microservice directory along the way (couple of directories have been renamed for data security reasons):

keytool -importcert C:\Users\jdoe\IdeaProjects\microservice\src\main\java\de\projectname\microservicename\geographical\files\googleapicert -keystore C:\Users\jdoe\IdeaProjects\microservice\src\main\java\de\projectname\projecttitle\geographical\files\truststore.jks -alias "jdoe"

Edit 3:

This is what my trust store looks like:

Keystore enthält 1 Eintrag

Aliasname: mykey
Erstellungsdatum: 31.07.2018
Eintragstyp: trustedCertEntry

Eigentümer: CN=*.googleapis.com, O=Google LLC, L=Mountain View, ST=California, C=US
Aussteller: CN=Google Internet Authority G3, O=Google Trust Services, C=US
Seriennummer: 78b8f1fdffefda73
Gültig von: Tue Jun 19 13:38:18 CEST 2018 bis: Tue Aug 28 13:31:00 CEST 2018
Zertifikatsfingerprints:
     SHA1: 0A:AA:3A:7D:F6:4D:56:32:0A:50:95:B5:60:D7:EA:46:A4:92:5A:A2
     SHA256: E8:E6:8E:47:F5:16:57:7A:C8:3E:8D:7E:6A:F2:3C:FB:CF:16:60:EF:38:FA:59:A4:0D:6E:22:16:21:0C:92:4E
Signaturalgorithmusname: SHA256withRSA
Public Key-Algorithmus von Subject: 2048-Bit-RSA-Schlüssel
Version: 3

Erweiterungen:

#1: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[accessMethod: caIssuers
 accessLocation: URIName: http://pki.goog/gsr2/GTSGIAG3.crt
  , accessMethod: ocsp
  accessLocation: URIName: http://ocsp.pki.goog/GTSGIAG3
]]

#2: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 77 C2 B8 50 9A 67 76 76   B1 2D C2 86 D0 83 A0 7E  w..P.gvv.-......
0010: A6 7E BA 4B                                        ...K
]]

#3: ObjectId: 2.5.29.19 Criticality=true
 BasicConstraints:[
 CA:false
 PathLen: undefined
]

#4: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
 [URIName: http://crl.pki.goog/GTSGIAG3.crl]
]]

#5: ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
[CertificatePolicyId: [1.3.6.1.4.1.11129.2.5.3]
[]  ]
[CertificatePolicyId: [2.23.140.1.2.2]
[]  ]]

#6: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
]

#7: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: *.googleapis.com
DNSName: *.clients6.google.com
DNSName: *.cloudendpointsapis.com
DNSName: cloudendpointsapis.com
DNSName: googleapis.com
]

#8: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: F9 74 1D 45 80 81 1C C1   17 A9 01 C4 A0 66 A0 7C  .t.E.........f..
0010: 91 A1 62 D5                                        ..b.
]]



*******************************************
*******************************************

My Geocoding class:

public class Geocoding {
@Value("${google.geocoding.api}")
private String googleAPIKey;

@Value("${google.geocoding.url}")
private String url;

final static Logger logger = Logger.getLogger(Geocoding.class);

private GeoApiContext context = new GeoApiContext.Builder()
        .apiKey(googleAPIKey)
        .build();

@ApiModelProperty
private String langauge;

private Gson gson = new GsonBuilder().setPrettyPrinting().create();

public Geocoding() {
}

public Geocoding(String googleAPIKey, String url) {
    this.googleAPIKey = googleAPIKey;
    this.url = url;
    this.context = new GeoApiContext.Builder().apiKey(googleAPIKey).build();
}

public String getLangauge() {
    return langauge;
}

public void setLangauge(String langauge) {
    if (langauge.length() > 1) {
        IllegalArgumentException ex = new IllegalArgumentException("illegal representation of a language code");
        throw ex;
    }
    this.langauge = langauge;
}

public String generateOutput(String request) {
    String output = url;
    request = request.replaceAll("\\s+", "+");
    List<String> deserializedString = Arrays.asList(request.split("\\s*,\\s*"));
    output = output.concat(deserializedString.get(0))
            .concat(",").concat(deserializedString.get(1)).concat(",")
            .concat(deserializedString.get(2)).concat("&key=").concat(googleAPIKey);
    return output;
}

public Address geoCodingResult(String address) throws Exception {

        GeocodingResult[] results = GeocodingApi.geocode(context, address).await(); //The application throws an SSL handshake exception right here

    }
}

These are the dependencies I've included in Gradle for Geocoding:

//Google Geocoding
compile 'com.google.maps:google-maps-services:0.2.8'
compile 'org.slf4j:slf4j-nop:1.7.25'
compile 'com.squareup.okhttp3:okhttp:3.10.0'

I've already checked both the Google API key and the geocoding url multiple times and they both seem to be correct, so I'm ruling out that that's the issue. I've also looked into the "newTrustStore" file with keytools and it does in fact have the Google Authority G3 certificate in it.

Help is much appreciated!

J. Doe
  • 31
  • 5
  • What's the exception? – Alastair McCormack Jul 30 '18 at 15:36
  • 1
    Are you the same person from this question? https://stackoverflow.com/questions/51348108/getting-ssl-sslhandshakeexception-when-using-rest-client-with-header-but-works-f/51348679#51348679 Anyways, see my answer, you might have added your certificate to a wrong trust store. Make sure that the trust store you add a certificate to is the same as the trust store used by the JRE on top of which your application is running. – Coder-Man Jul 30 '18 at 16:04
  • why would you use a custom trust store? the root CAs for any google TLS should be in you global trust store already ... – rmalchow Jul 31 '18 at 04:03
  • @AlastairMcCormack: It's an SSL Handshake Exception, as stated in the title of the question. – J. Doe Jul 31 '18 at 07:38
  • @Wow: No, this is my first time asking a question on this board. I've already followed the exact steps you laid out, but still no luck. I've already checked if the trust store I'm linking to in the application properties is the correct one (via keytools) and it is. It does have the Google Authority G3 certificate in it but the error still persists. – J. Doe Jul 31 '18 at 07:44
  • @rmalchow: Running the application with the root CAs / global trust store doesn't seem to work correctly with IntelliJ for some reason. Putting a custom trust store into the application directory is also a safety measure to make sure the key- and truststore are functioning on all machines that use this microservice – J. Doe Jul 31 '18 at 07:44
  • @J.Doe Welcome to Stackoverflow. To help people resolve your question, you need to provide as much detail as necessary. You also need to make sure you don't fall into the XY problem where you bring the wrong answer in your question (See https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). When I asked for the exception, I was asking for the specific exception, **including the message** and relevant stacktrace. Please update your question. – Alastair McCormack Jul 31 '18 at 07:57
  • @J.Doe further, an SSLHandshakeException covers a multitude of reasons for failing to negotiate an SSL session. It's very important to include the message in your questions. – Alastair McCormack Jul 31 '18 at 08:15
  • @AlastairMcCormack: Thank you and sorry for my error! The precise error message I get 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 – J. Doe Jul 31 '18 at 08:15
  • Cool thanks. What command did you use to import the cert into the truststore? – Alastair McCormack Jul 31 '18 at 08:38
  • @J.Doe ok, yes. this is understandable. could you edit your question to include your answers? that would improve the question a lot, i think. – rmalchow Jul 31 '18 at 08:43
  • That would be keytool -importcert C:\Users\jdoe\IdeaProjects\microservice\src\main\java\de\projectname\projecttitle\geographical\files\googleapicert -keystore C:\Users\jdoe\IdeaProjects\microservice\src\main\java\de\projectname\projecttitle\geographical\files\truststore.jks -alias "jdoe" – J. Doe Jul 31 '18 at 08:44
  • @AlastairMcCormack: I moved the google certificate into my java project directory and tried to save my truststore right there also – J. Doe Jul 31 '18 at 08:45
  • @rmalchow: Yes sure! – J. Doe Jul 31 '18 at 08:45
  • @j.doe oh, you already did. also: could you post the certificate? either as pem or just tge output of openssl x509 -in $PATH_TO_CERT -text -noout – rmalchow Jul 31 '18 at 08:47
  • Which Java runtime are you using? I’d advise at least Java 8. –  Jul 31 '18 at 08:50
  • @rmalchow: I've posted the contents of the trust store in the original post! – J. Doe Jul 31 '18 at 09:03
  • @mrblewog: I'm using OpenJDK 10.0.1 – J. Doe Jul 31 '18 at 09:04

2 Answers2

4

I faced same issue while using com.google.maps:google-maps-services on OpenJDK 10 which does not trust Google Internet Authority G3 for some reason.

To fix this it's better to import missing certificate to the system-wide keystore (usually found in $JAVA_HOME/lib/security/cacerts) using keytool:

wget http://pki.goog/gsr2/GTSGIAG3.crt
keytool -import -alias GTSGIAG3 -file GTSGIAG3.crt -keystore $JAVA_HOME/lib/security/cacerts

Then enter the password if prompted (the default is changeit).

If you are using Docker, you can import missing certificate using a following command:

FROM openjdk:10-jre-slim

RUN apt-get -qqy update \
    && apt-get -qqy --no-install-recommends install wget \
    && wget http://pki.goog/gsr2/GTSGIAG3.crt \
    && yes | keytool -import -alias GTSGIAG3 -file GTSGIAG3.crt -keystore $JAVA_HOME/lib/security/cacerts -storepass 'changeit' \
    && rm GTSGIAG3.crt \
    && apt-get -qqy purge wget \
    && rm -rf /var/lib/apt/lists/* /var/cache/apt/*
Yegor Usoltsev
  • 136
  • 1
  • 5
  • Thank you very much! I also came to this conclucsion eventually but didn't post it here for some reason. This solution works. – J. Doe Oct 12 '18 at 07:45
1

i am wondering: if you are in maven, then resources in

 src/main/java/.... 

will NOT end up in the jar. that directory is for classes only. to have it in the output, put the truststore in

 src/main/resources

also, you will probably have to adjust the path. it might be something like:

classpath:/path/within/the/resources/folder/trustStore

or just:

path/within/the/resources/folder/trustStore
rmalchow
  • 2,689
  • 18
  • 31
  • Thank you a lot, I will try your solution and let you know if it worked! – J. Doe Jul 31 '18 at 11:08
  • Unfortunately, your solution didn't work out, the application still throws the same error message. – J. Doe Aug 01 '18 at 07:43
  • just for clarification - you see this error both when running from a jar AND when running from your IDE? did you verify that you have the right cert using openssl? e.g. "openssl verify -verbose -CAfile <(cat Intermediate.pem RootCert.pem) UserCert.pem"? – rmalchow Aug 02 '18 at 06:24
  • also - are you sure that the google libraries honor the trust store config from spring? maybe you can try to to a RestTemplate request to the API endpoint? – rmalchow Aug 02 '18 at 06:26