tls – SSL Certificate – Information Security Stack Exchange

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).