Subject: [pgjdbc/pgjdbc] issue #3942: File extension-based format detection breaks DER keys with .key suffix

From: "reissseb (@reissseb)" <[email-masked]>
Date: Fri, 20 Feb 2026 16:20:50 +0000

This is more of informational purpose for others stumbling upon this problem as well.

It would be nice to update the documentation to clearly state which file format is expected for each file ending.

**Describe the issue**

I updated our Spring Boot application from 3.5.8 to 3.5.11, which includes pgjdbc version v42.7.9.

PR [#3700](https://github.com/pgjdbc/pgjdbc/pull/3700) added PEM support and introduced file extension-based format detection in `LibPQFactory.java`:

```java
} else if (sslkeyfile.endsWith(".key") || sslkeyfile.endsWith(".pem")) {
   initPEM(sslkeyfile, defaultdir, info);
} else {
   initPk8(sslkeyfile, defaultdir, info);
}
```

This change now associates `.key` files with PEM format.

In our case, we were using DER-formatted keys with `.key` extension, which resulted in `MalformedInputException`.

**Solution**

Renaming the key file to use the `.der` extension solved the problem.

**Expected behavior**

Document that `.key` and `.pem` extensions expect PEM text format.

**Driver Version**

v42.7.10

**To Reproduce**

1. Create a DER-formatted private key file with `.key` extension
2. Set `sslkey` parameter in JDBC URL to point to this file
3. Attempt to connect

**Logs**

```
Caused by: org.postgresql.util.PSQLException: Could not load the private key
       at org.postgresql.ssl.PEMKeyManager.getPrivateKey(PEMKeyManager.java:80)
       ...
Caused by: java.nio.charset.MalformedInputException: Input length = 1
       at java.base/java.nio.charset.CoderResult.throwException(Unknown Source)
       at java.base/sun.nio.cs.StreamDecoder.implRead(Unknown Source)
       at java.base/sun.nio.cs.StreamDecoder.read(Unknown Source)
       at java.base/java.io.InputStreamReader.read(Unknown Source)
       at java.base/java.io.BufferedReader.fill(Unknown Source)
       at java.base/java.io.BufferedReader.readLine(Unknown Source)
       at java.base/java.io.BufferedReader.readLine(Unknown Source)
       at java.base/java.nio.file.Files.readAllLines(Unknown Source)
       at java.base/java.nio.file.Files.readAllLines(Unknown Source)
       at org.postgresql.ssl.PEMKeyManager.getPrivateKey(PEMKeyManager.java:50)
```

---

From: "sehrope (@sehrope)" <[email-masked]>
Date: Sun, 22 Feb 2026 16:40:46 +0000

Yes this is a regression. Thanks for the report.

I believe the intention of LibPQFactory is to match the default behavior of libpq whenever possible. It's a bit different here (even before the PEM support PR) as historically we support Java's native key stores for certs. In libpq they try loading the key twice and only report the second error: https://github.com/postgres/postgres/blob/412f78c66eedbe9cf41a657f4566d86a69ab7af2/src/interfaces/libpq/fe-secure-openssl.c#L1276-L1302

That works fine for the happy path where the key can be read correctly in some manner. But might give a not so great error if it's really the first type that's tried. Probably fine though as it does not stop you from being able to connect when you otherwise could (just the error message is not that helpful).

I think we need to do something similar here as well. Maybe we also offer a separate driver option to instruct how to pick (e.g, default of "auto" that tries all options, but explicit "PEM" etc to force only one attempt at the known type).

I don't like any of the file extension based checks. I think we might be able to remove them with the "auto" option as the change would only be in the possible not-so-great error message if it fails. Be simpler than trying to handle file extensions and an entire separate code path.

@davecramer @vlsi Thoughts?

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Mon, 23 Feb 2026 11:30:25 +0000

I think we should try to mimic libpq as much as possible. Interesting the way they do it. Seems like it would work for us too.

---

From: "davecramer (@davecramer)" <[email-masked]>
Date: Tue, 24 Feb 2026 11:58:47 +0000

@sehrope do you have any cycles to work on this ?

---

From: "sehrope (@sehrope)" <[email-masked]>
Date: Tue, 24 Feb 2026 12:06:34 +0000

Was planning on it but looks like @vlsi already has something going.

---

From: "vlsi (@vlsi)" <[email-masked]>
Date: Tue, 24 Feb 2026 12:25:21 +0000

I don't quite like "dynamic detection" due to current lazy key loading in X509KeyManager implementation. However, it looks like  the overall changes are not that devastating, so we could probably support "dynamic pem vs pk8" detection logic.