Search code examples
sslrabbitmqssl-certificaterabbitmq-c

When/why would you need to use CACert in a TLS negotiation?


I am trying to understand the parameters used to configure TLS (specifically for rabbitmq but my question might be more general).

There are 4 main entities to consider:

  • Key - private key used by a peer to decrypt messages send to it that have been encrypted using its public key.

  • Cert - A certificate containing the peers public key It also contains some identifying details like hostname, organisation etc. many of which are optional. A certificate could be unsigned (rarely if ever?), self-signed or signed by a certificate authority.

  • CACert - the certificate of a CA trusted by the peer which can be used to decrypt and verify the signature of a signed cert.

  • CA-key - the private key of the CA which it used to sign a cert.

These map to configuration settings including:

  • enablePeerVerification - If true then a peer tries to verify the server is who it says it is by checking the certificate really was signed by the CA (and likewise up the chain of trust until it reaches a CA it trusts because it has a cert in its local CA trust store). It is a bad idea to set this to false as someone could impersonate the peer. (in go this option is called InsecureSkipVerify as a warning) If the cert is self-signed, peer verification is impossible. This option allows you to use a peer's self-signed cert instead at your own risk (e.g. during development).

  • Key - the private key used for decryption

  • Cert - used for encryption (and handshaking)

  • CACert - the certificate of the CA who signed the "Cert" certificate

Why are there configuration settings for the CACert?

If the cert is signed by a CA then it already contains enough information to locate the CA (e.g. domain name). What is the CACert for and if or when is it sent during TLS negotiation? Is this just a convenience to save going off to the CA directly? You will still have to do this if the CACert does not match or point to one in your trust store.

The settings I'm referring to are "cacert" in the rabbitmq.config for the server and amqp_ssl_socket_set_cacert() in the C API (rabbitmq-c).

I would like to check that my understanding is correct (https://xkcd.com/386/)


Solution

  • First the CA private key here is irrelevant here since by definition it is private and hence you never have it, except if you do self signed certificates.

    The TLS handshake is:

    • the server you are connecting to sends you its certificate and, optionnally, a list of intermediate certificates up to the root (CA), that last one being also optional and often not sent as the client is supposed to have it already in its truststore
    • if the server requests a client certificate it sends the list of CAs it will accept for the client certificate (it is an hint to help the client choose the proper certificate to send)
    • so if it needs to, the client sends its certificate and in the same way as first point, a potential list of intermediate certificates up to some root.

    Depending on the client you may then have multiple configuration items: - the list of certificates to send as intermediate (either as a path to some directory or a single file with all of them in it) together with its own client certificate - the list of certificates you use (again a directory or a file) as fully trusted to verify the server certificate.

    Often, these two settins are only one.

    Now:

    If the cert is signed by a CA then it already contains enough information to locate the CA (e.g. domain name).

    Not sure to understand you, but in general no. First a certificate is not necessarily/only for a domain name it can be for other things. Then a certificate is typically signed by an intermediate, not directly by the CA. So I am not sure how you want to locate the CA?