How to configure openssl client to only accept specific server certificates?

I'm new to this community and kind of to things related to security.

I have three servers

  • Web Server (Client)
  • Mail Server (eSMTP)
  • Web Server

All servers have their own SSL certificates and got asked to do the following:

Web server (client) has to make secure requests to other two servers with TLS and only accept the certificates from those servers and nothing more. Is there a way to configurate this in openssl? My issue is, the certificates are local/self-signed.

The client server is a RHEL 7.


Solution 1:

The practice you're talking about is called "Certificate Pinning" (or sometimes "Public Key Pinning") and is a common security recommendation when you control both the client and the server.

Typically this is done by configuring the TLS client code (which might be OpenSSL or some other library) to introduce a custom certificate validation step (typically a function to call when the connection is being established), and in that step you verify that the certificate presented by the server matches the one you were expecting. You might want to look at https://stackoverflow.com/questions/16291809/programmatically-verify-certificate-chain-using-openssl-api or https://stackoverflow.com/questions/3412032/how-do-you-verify-a-public-key-was-issued-by-your-private-ca for code samples to do this (though those are old and might be outdated); OpenSSL's API is very easy to make mistakes with.

You might also want to read https://labs.nettitude.com/tutorials/tls-certificate-pinning-101/ or similar, which talk about the considerations when doing pinning. In particular, you want to consider things like which cert you pin (a specific leaf cert, the root CA, or something in between) and how much of the cert you pin (pinning the whole cert seems easy but complicates re-issuing the cert with new dates or OIDs or similar, whereas simply pinning public key details provides all the security you really need in most cases). You should also consider a backup / fallback pin, to make cert rotation easier in case your primary cert gets compromised and needs to be revoked.


With all that said, there might be another option in this case. If your client (which is also a server) is only ever going to connect to this one other server, and you use an internal CA, you can configure the TLS client code to use a CA "bundle" containing just that internal CA's cert, rather than using the system-wide CA bundle. That lets you keep using the default cert validation code, it just won't trust any certificate that doesn't chain to your internal CA. This is de facto the same as pinning at the CA level, but potentially much simpler (though with less fine control over the validation logic).