Multiple Client Certificate Selection – a Simple POC

Enterprise PostgreSQL Solutions

Comments are off

Multiple Client Certificate Selection – a Simple POC

Introduction

I recently came across this email thread discussion from several years ago, which discussed ways to enable a client to choose from a list of client certificates to send to the server. The benefit is obvious; when a client has to communicate with different PostgreSQL servers with different TLS settings and trust structure, the feature can help reduce the application’s effort to figure out what certificate to send to what server. In other words, the application does not need to have this selection logic because the libpq library is able to choose the right one to send.

OpenSSL provides PostgreSQL with TLS and other cryptographic capabilities and it has also evolved significantly over the past years. Now, it has much more API support that enabled applications to make more informed TLS decisions. For example, choosing the most appropriate client certificate to send to the server during handshake. Today, in this post, I will briefly explain how certificate chain of trust works and share the “multiple client certificate selection” patch if one is intereted.

TLS ? Certificate ? Trust Chain? What?

TLS (Transport Layer Security)

formerly called SSL (Secured Socket Layer). Now the two terms are used interchangeably. This is a protocol for encrypting and protecting network communications. It has 2 major responsibilities:

  • Communication encryption / decryption + integrity check
  • Use certificates to verify the identities of both parties.

Certificate

Also called X509 v3 Certificate, or simply X509 Certificate. It is a data structure that contains validity, issuer, extension, purpose and other custom information. Primarily used to represent an entity’s identity and ensure trust. It has three basic types:

  • Certificate Authority – Also called CA Certificate or root CA. (IdenTrust, DigiCert, GlobalSign, Let’s Encrypt, etc are common CAs. It can also be self-signed for test purposes).
  • Intermediate CA certificate.
  • Entity Certificate – The actual certificate used for communication. They are exchanged during the TLS handshake. For most cases, the server sends its certificate to a client for verification only, but in some cases, client also has to send its certificate to the server to verify. Also known as mutual verification.

Trust Chain

One of the criteria to determine whether a entity certificate can be trusted. If we were able to “establish” a path from this certificate all the way to the a trusted root CA, then the certificate can be trusted (given that it has not expired). This “path” describes how many “signers” are involved in the issuing of this certificate. This path is also called a trust chain.

Some Examples

Consider this certificate setup, where client and server certificates are signed by intermediate CA 1 and 2, both issued by a common root CA.

The No Trust Case

If a PostgreSQL client and server have the following certificate configurations, they will not trust each other, because either end is not able to establish a trusted path to the common root CA.

The Trust Case

If a PostgreSQL client and server have the following certificate configuration, they can trust each other, because both ends are able to establish a trusted path to the common root CA:

  • Client Certificate -> Intermediate CA 1 -> Root CA
  • Server Certificate -> Intermediate CA 2 -> Root CA

Combined Intermediate CA and Entity Certificate Case

There is a case where both PostgreSQL client and server only have Root CA certificate configured as the “trust anchor”. They do not have any intermediate CA certificate configured most likely because they do not know how many there even are.

To ensure the trust, we can alternatively append the intermediate CA certificates in the same entity certificate file (indicated by dash line below) and send to the other peer. This is important because the client or the server can use the intermediate CA certificate received to build the path to the common root CA, and therefore in the case below, both client and server can trust each other.

Multiple Client Certificate in PostgreSQL

Now that we know the basics how TLS protocol ensures trust between client and server with the help of certificates and trust chains. We can then look at how we can make PostgreSQL’s libpq client to choose the best certificate to send. Here’s the approach:

1. add 2 new connection parameters sslcertdir and sslkeydir in addition to sslcert and sslkey that the library already support. The 2 new parameters indicate the paths to a directory where all certificate and private key candidates will be located. It will pick the best one to use from these directories.

2. Register a cert_cb callback function, which will be invoked by OpenSSL during handshake, when client receives “Certificate Request” from the server. This gives us a chance to do some logic an set a desired certificate to send to the server. The following illustrates when cert_cb is invoked. Verfiy_cb is also invoked to give us a chance to check peer certificate. We will not modify this one.

3. inside cert_cb, we will call SSL_get0_peer_CA_list(ssl) to obtain a list of CA names configured at the server side. This list will help client to choose a certificate. The criteria is this, if a certificate’s issuer name equals to one of the CA names received, that is the certificate to use. This works for most times, but with a limitation, which we will talk about it later.

4. Open the sslcertdir and try to find the certificate with the matching criteria mentioned in 3. If one is found, we then try to look for a matching key from sslkeydir.

5. Finally, we will set the new certificate and key before returning the cert_cb function so that the handshake can continue.

Limitation

1. The client certificate selection feature works only when all the possible CA certificates are configured at the server side. This includes all root CA and intermediates certificates, with an assumption that all intermediate CA certificates configured can be trusted. Yet, this may not always be the case.

2. If the client certificate is issued by an intermediate certificate and the server does not have it configured along with its root CA, the selection feature may not work properly. This is because the feature relies on trusted CA name to make a selection, it does not yet analyze potential intermediate CA certificates appended to the same client certificate file. This can be enhanced in future version.

3. Encrypted private key file: If a private key file under sslkeydir is encrypted by a password, it can only use the same password (as configured by sslkeypassword option). It is not able to use different password to decrypt different key file while searching for the matching key.

The Patch

The POC patch for this feature can be found here. You are welcome to try it out.