gRPC Protocol - use CustomCertificate TrustManager

I am using Gatling 3.13.1 with Maven and need help configuring a gRPC request with a self-signed certificate.

Setup

I have generated the following files and used them to start my gRPC server:

  • privateKey.pem
  • certificate.pem

To verify that the server works correctly, I wrote a Java main method that successfully makes a request to the server (code is not provided now but I can provide it if needed it). However, when trying to perform the same request using Gatling, I run into an issue.

Gatling Configuration

I have a configuration file where I define the necessary properties:
grpcHost=localhost
grpcPort=9091
certificate.path=path/to/certificate.pem

I then read these properties in my Gatling setup:

String certificatePath = configProperties.getProperty(“certificate.path”);
return grpc.forAddress(configProperties.getGrpcHost(), configProperties.getGrpcPort())
.useCustomCertificateTrustManager(certificatePath);

This method returns a GrpcProtocolBuilder. I have also tried .useStandardTrustManager(), but the issue remains the same.

Error Message

When executing the test in Gatling, I receive the following error:

gRPC stream end:
status:
code: UNAVAILABLE
description: io exception
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]
cause: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem

I suspect I am missing something in my Gatling configuration. Could you help me identify the issue and guide me on how to correctly pass the self-signed certificate to Gatling for gRPC requests?

I would really appreciate any insights!

I’ve triple check this part of the code and I fail to see how there could be an issue there.

Possible issues (some might sound stupid, but better safe than sorry as we’ve encountered them):

  • you’ve made a mistake while copying the correct certificate into your project
  • the certificate is not in X509 format
  • certificate.path must be a classpath path, eg the relative path from src/test/resources, not a filesystem path
  • the code version you’re executing is not the one you have locally (eg forgot to push on a git repo or to re-upload a package)
  • you’ve made a mistake while copying the correct certificate into your project

I verified that I copied the correct certificate from my gRPC server.

  • the certificate is not in X509 format

I double-checked, and the certificate is in X.509 format.

  • certificate.path must be a classpath path, eg the relative path from src/test/resources, not a filesystem path

Initially, I was using an absolute path:
C:/Users/myuser/path/to/certificate.pem.
I corrected it to a classpath path:
src/main/resources/certificate.pem and I am able to see information about certificate (as before).
My Java code reads the certificate as follows:
String certificatePath = configProperties.getProperty(“certificate.path”);
CertificateFactory certificateFactory = CertificateFactory.getInstance(“X.509”);
FileInputStream certInputStream = new FileInputStream(certificatePath);
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(certInputStream);

            log.info("Certificate's information:");
            log.info("Issuer: {}", certificate.getIssuerDN());
            log.info("Subject: {}", certificate.getSubjectDN());
            log.info("Serial Number: {}", certificate.getSerialNumber());
            log.info("Not Before: {}", certificate.getNotBefore());
            log.info("Not After: {}", certificate.getNotAfter());
            log.info("Signature Algorithm: {}", certificate.getSigAlgName());
            return grpc.forAddress(configProperties.getGrpcHost(),configProperties.getGrpcPort())
                    .useCustomCertificateTrustManager(certificatePath);

Output of above logs
Certificate’s information:
Issuer: CN=localhost
Subject: CN=localhost
Serial Number: 721581440726280250068496780889873755888237740866
Not Before: Mon Mar 31 22:06:18 EEST 2025
Not After: Tue Mar 31 22:06:18 EEST 2026
Signature Algorithm: SHA256withRSA

  • the code version you’re executing is not the one you have locally (eg forgot to push on a git repo or to re-upload a package)

I am running this locally, so there is no issue related to uncommitted or outdated code from a Git repository.

Behavior Without SSL when using
grpc.forAddress(configProperties.getGrpcHost(), configProperties.getGrpcPort())
.usePlaintext();
or
grpc.forAddress(configProperties.getGrpcHost(), configProperties.getGrpcPort())
.useInsecureTrustManager();

the gRPC service is accessible, meaning the connection works without certificate validation.

I do agree with you that most probably I miss something small and could be something stupid.

Do you have any other idea what could be wrong?
Are there any additional logs I could enable to get more insight into the problem?
Would it help if I provided details on how I created my self-signed certificate?

Any ideas or suggestions would be greatly appreciated!

Update: I run my simulation with command ‘mvn gatling:test’

I corrected it to a classpath path:
src/main/resources/certificate.pem and I am able to see information about certificate (as before).

My Java code reads the certificate as follows:
String certificatePath = configProperties.getProperty(“certificate.path”);

This is wrong.

src/main/resources/certificate.pem is a relative filesystem path, not a classpath path.

You should actually be passing certificate.pem (with certificate.pem being located in src/main/resources).

You should actually be passing certificate.pem (with certificate.pem being located in src/main/resources).

Issue is fixed!
certificate located into: src/main/resources/certificate.pem
So I pass (as you said) certificate.pem and it is working with no problem.

many thanks!

with certificate.pem being located in src/main/resources

Is it strictly required to place certificate.pem inside src/main/resources or src/test/resources, or are there alternative locations where it can be stored?

So I pass (as you said) certificate.pem and it is working with no problem.

Great news. Still, I would have expected us to detect that the resources is missing and crash upfront. I’ll investigate.

Is it strictly required to place certificate.pem inside src/main/resources or src/test/resources , or are there alternative locations where it can be stored?

Strictly required.
Note that there’s nothing sensitive in this file.

Great news. Still, I would have expected us to detect that the resources is missing and crash upfront. I’ll investigate.

That’s why I asked you if I can open some more logs to see where exactly it is failing.

Strictly required.
Note that there’s nothing sensitive in this file.

Clear.

Strictly required.

Note: I’m going to change this to align with standard Gatling behavior regarding certificates and allow absolute paths too.

That’s why I asked you if I can open some more logs to see where exactly it is failing.

Yeah, I see that our gRPC plugin doesn’t reuse core Gatling’s Ssl helper. Fixing.

Note: I’m going to change this to align with standard Gatling behavior regarding certificates and allow absolute paths too.

Do you have any ETA for this? :slight_smile:

Not sure, maybe next month.

1 Like