Keystore errors in Sonar Gradle Scanner 6.x

  • Environment: GitHub Actions, Large Ubuntu Runner
  • JDK = 17 (Temurin)
  • Gradle: 7.5 (AGP 7.4.2)
  • Server: Sonar Developer 10.3 (Yeah, I know)
  • Sonar Gradle Plugin: 6.1.0.5360

Hey folks, having some issues with the Sonar Gradle plugin in our CI setup, was hoping to get some assistance. We’re building an Android app that’s a little behind current but not catastrophically so.

The Sonar 5.x Gradle plugin started failing in our CI setup where it had previously worked OK, array-out-of-bounds stuff. Seemed like a bug (codebase got too big?) and I saw that the 6.x scanner was available, so I figured it would be smarter to upgrade the plugin instead.

This has itself caused me problems because the system cacerts file is in JKS format.

Original error message:

Caused by: nl.altindag.ssl.exception.GenericKeyStoreException: Unable to read truststore from '/usr/lib/jvm/temurin-17-jdk-amd64/lib/security/cacerts'
	at org.sonarsource.scanner.lib.internal.http.OkHttpClientFactory.configureSsl(OkHttpClientFactory.java:146)
	at org.sonarsource.scanner.lib.internal.http.OkHttpClientFactory.create(OkHttpClientFactory.java:80)
	at org.sonarsource.scanner.lib.internal.http.ScannerHttpClient.init(ScannerHttpClient.java:52)
	at org.sonarsource.scanner.lib.ScannerEngineBootstrapper.bootstrap(ScannerEngineBootstrapper.java:147)
	at org.sonarqube.gradle.SonarTask.run(SonarTask.java:134)
	... 144 more
Caused by: java.io.IOException: stream does not represent a PKCS12 key store

I tried providing overrides to tell Sonar that the keystore is in JKS, but the flags I found for that on the net didn’t seem to work. Turns out that the Sonar Scanner’s Java library is now hard-coded to only accept PKCS12 stores.

So I tried converting the store:

        keytool \
          -importkeystore \
          -srckeystore "$JKS_TRUST_STORE" \
          -srcstoretype jks \
          -destkeystore "$PKCS12_TRUST_STORE" \
          -deststoretype pkcs12 \
          -srcstorepass changeit \
          -deststorepass changeit \
          -noprompt

And then providing the new store location to the build:

./gradlew androidBuildNameHere sonar -x lint --profile --stacktrace \
  -Dsonar.token=${{ secrets.SONAR_SECRET_TOKEN }} \
  -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \
  -Dsonar.scanner.truststorePath=${{ env.TRUST_STORE }} \
  -Dsonar.scanner.truststorePassword=changeit \
  -Dsonar.scanner.keystorePath=${{ env.TRUST_STORE }} \
  -Dsonar.scanner.keystorePassword=changeit

Now the scanner can access the store, but still doesn’t like it:

Caused by: nl.altindag.ssl.exception.GenericKeyStoreException: Unable to read truststore from '~/.sonar/ssl/truststore.p12'
	at org.sonarsource.scanner.lib.internal.http.OkHttpClientFactory.configureSsl(OkHttpClientFactory.java:146)
	at org.sonarsource.scanner.lib.internal.http.OkHttpClientFactory.create(OkHttpClientFactory.java:80)
	at org.sonarsource.scanner.lib.internal.http.ScannerHttpClient.init(ScannerHttpClient.java:52)
	at org.sonarsource.scanner.lib.ScannerEngineBootstrapper.bootstrap(ScannerEngineBootstrapper.java:147)
	at org.sonarqube.gradle.SonarTask.run(SonarTask.java:134)
	... 116 more
Caused by: java.io.IOException: exception decrypting data - java.security.InvalidKeyException: Wrong algorithm: AES or Rijndael required
	at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.cryptData(Unknown Source)
	at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineLoad(Unknown Source)
	at org.sonarsource.scanner.lib.internal.http.OkHttpClientFactory.loadKeyStoreWithPassword(OkHttpClientFactory.java:185)
	at org.sonarsource.scanner.lib.internal.http.OkHttpClientFactory.loadTrustStoreWithBouncyCastle(OkHttpClientFactory.java:169

I must admit, the various moving parts of cryptography aren’t my strength. What do I need to be doing here to make Sonar happy when executing? Every piece of documentation I can find is on creating a store to hold self-signed certificates, but the server has a proper 3rd party signed certificate. Sonar just doesn’t like the system keystore. Would appreciate any assistance you can provide.

Hi,

Welcome to the community!

This SO answer may help.

 
Ann

I did eventually figure this out by locating OpenJDK’s own conversion command that makes the trust store unprotected. It only exists for the length of the build so that’s fine IMO.

mkdir -p $(dirname "$PKCS12_TRUST_STORE")
keytool \
  -J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE \
  -J-Dkeystore.pkcs12.macAlgorithm=NONE \
  -importkeystore \
  -srckeystore "$JKS_TRUST_STORE" \
  -srcstorepass changeit \
  -deststoretype pkcs12 \
  -destkeystore "$PKCS12_TRUST_STORE" \
  -noprompt

That fixes the trust store issue, but I immediately ran into another issue. I seem to be hitting a classpath issue with the scanner. It’s using an embedded Eclipse compiler, and that’s causing a package conflict? Is there a way for me to tell the scanner to use the same JDK as the project?

Status ERROR: org.eclipse.jdt.core code=4 Could not retrieve interfaces org.eclipse.jdt.internal.compiler.problem.AbortCompilation: Pb(347) The type java.lang.String cannot be resolved. It is indirectly referenced from required type android.view.Window
Status ERROR: org.eclipse.jdt.core code=4 Could not retrieve declared methods org.eclipse.jdt.internal.compiler.problem.AbortCompilation: Pb(347) The type java.lang.String cannot be resolved. It is indirectly referenced from required type android.content.SharedPreferences.OnSharedPreferenceChangeListener
ECJ Unable to resolve type android.content.ContentProvider
org.eclipse.jdt.internal.compiler.problem.AbortCompilation: Pb(347) The type java.lang.String cannot be resolved. It is indirectly referenced from required type android.content.ContentProvider
	at org.eclipse.jdt.internal.compiler.problem.ProblemHandler.handle(ProblemHandler.java:162)
	at org.eclipse.jdt.internal.compiler.problem.ProblemHandler.handle(ProblemHandler.java:229)
	at org.eclipse.jdt.internal.compiler.problem.ProblemReporter.handle(ProblemReporter.java:2679)
ECJ Unable to resolve type org.apache.commons.lang3.RandomStringUtils
org.eclipse.jdt.internal.compiler.problem.AbortCompilation: Pb(347) The type java.lang.String cannot be resolved. It is indirectly referenced from required type org.apache.commons.lang3.RandomStringUtils
	at org.eclipse.jdt.internal.compiler.problem.ProblemHandler.handle(ProblemHandler.java:162)
	at org.eclipse.jdt.internal.compiler.problem.ProblemHandler.handle(ProblemHandler.java:229)

I did see this thread with the same issue, but the related issue appears to be fixed. I’m not entirely sure why Sonar would be compiling anything at all, as the build was already done by Gradle/AGP, and the Sonar Scanner lists Java 17 as a pre-requisite.

Hi,

I think you’re looking for sonar.scanner.skipJreProvisioning=true.

 
HTH,
Ann

Tried it, no effect unfortunately. I also tried manually setting source and target. Current command I’m running is:

./gradlew sonar -x lint --stacktrace \
  -Dsonar.token=${{ secrets.SONAR_SECRET_TOKEN }} \
  -Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \
  -Dsonar.scanner.truststorePath=${{ env.TRUST_STORE }} \
  -Dsonar.scanner.truststorePassword=changeit \
  -Dsonar.scanner.keystorePath=${{ env.TRUST_STORE }} \
  -Dsonar.scanner.keystorePassword=changeit \
  -Dsonar.scanner.skipJreProvisioning=true \
  -Dsonar.java.jdkHome=$JAVA_HOME \
  -Dsonar.java.source=11 \
  -Dsonar.java.target=11

Hi,

Try the sonar.java.jdkHome property, and if that doesn’t work, then give us your analysis log (--info level, please).

The analysis / scanner log is what’s output from the analysis command. Hopefully, the log you provide - redacted as necessary - will include that command as well.

This guide will help you find them.

 
Ann

I did get the logs out, and reviewing them I may have spotted the issue. I had assumed that the scanner bundled its scanning libraries or retrieved them from a central dependency repository, but what I had not realised is that the scanner is downloading libraries from our server on each run. As noted in the first post, our server is outdated (I’m waiting on gaining access to upgrade it). Looking at the versions involved, we’re exactly one server version behind the fix. Dang it!

I will get the server upgraded and either mark this thread as resolved or continue it if the problem persists. Thank you for your help, @ganncamp

1 Like