2

We have an interesting discussion between the server operator team and the developers of a client application.

Our setup in general is like this: There is a root-ca, let's call it "root-1". This has a sub-ca, let's call it "sub-1". Both are contained in the server's truststore. The client has got a combined key- / truststore (i.e. the same keystorefile), containing the ca chain mentioned above and a client-certificate issued by sub-1. Let's call this "client-1".

During the TLS handshake, the server sends a CertificateRequest message, containing a list of DN which are trusted (because they are in the truststore), i.e. ["root-1", "sub-1"].

The client checks the list, recognizes that it has a certificate issued by "sub-1" and sends that certificate as a certificate_list with one single entry: the client certificate.

The server operators are stating that the client should send the whole certificate chain, but may omit the root-ca. Basically, they like to delete "sub-1" from their truststore so that only "root-1" will be requested by the server. The client should find "client-1" which is issued by "sub-1" which is issued by "root-1" and then send the whole certificate chain.

The client developers are stating that this is a security breach or is at least less secure than the current solution. They say it seems like the server will then validate the client certificate agains the trustchain the client has sent by itself.

So from my point of view there are two questions resulting out of this discussion: 1. If the server requests only "root-1", should the client find "client-1" as an appropriate certificate an use it for communication? 2. If the answer to the first question would be yes, should the client send the certificate chain, i.e. [client-1, sub-1] (omitting root ca according to rfc)?

The RFC 5246 might be a little fuzzy in that section:

7.4.6.  Client Certificate
[...]
Client certificates are sent using the Certificate structure
      defined in Section 7.4.2.

And Section 7.4.2 says:

    7.4.2.  Server Certificate
[...]
   Structure of this message:

      opaque ASN.1Cert<1..2^24-1>;

      struct {
          ASN.1Cert certificate_list<0..2^24-1>;
      } Certificate;

   certificate_list
      This is a sequence (chain) of certificates.  The sender's
      certificate MUST come first in the list.  Each following
      certificate MUST directly certify the one preceding it.  Because
      certificate validation requires that root keys be distributed
      independently, the self-signed certificate that specifies the root
      certificate authority MAY be omitted from the chain, under the
      assumption that the remote end must already possess it in order to
      validate it in any case.

The client developer now is interpreting this section like this:

Each following certificate MUST directly certify the one preceding it.

This means, that there MUST not be a certificate following the "senders certificate" i.e. the client certificate. Because the same structure is used for server and client certificate, the certificate_list has a length of 0..2^24-1. This means the list is valid with 0, 1, or multiple entries.

My thinking on that one is this:

  • if the server has "sub-1" NOT in its truststore, it will use the ca the client is sending for validation, which sounds less secure to me. An attacker could produce a somehow valid "sub-2", then create a client certificate using "sub-2", send the chain and will be authenticated.
  • A revocation list for CAs will not work then, because the rogue ca "sub-2" is unknown
  • what is the advantage having only the root-ca in the server's truststore and having a client sending the whole certificate chain?

Additional information: the client is a middleware, too, so there is no possibility of any user interaction.

The client developers fear that the processing intended by the server operators brings serious security issues, which would be otherwise easily avoided. For them it makes no sense to send the sub-ca along with the client certificate, because the server should actually TRUST the sub-ca. That's why the sub-ca should reside in the server's truststore.

The server operators are saying, it would be of great effort to maintain always a set of valid sub-cas in their server's truststore, because there may be new sub-cas coming up, without their knowledge or attention. Furthermore they say, the behaviour of the client is not compliant with TLS 1.2 and that they are urged to use TLS 1.2.

But I cannot find any differences in the CCA (Client Certificate Authentication) area between TLS 1.0 and TLS 1.2. It is the same text there.

I will appreciate any clarification of this issue by any of the security experts here.

  • How do you maintain similar scenarios in your projects? When implementing TLS 1.2 compliant clients, are you sending the certificate chain or a single certificate?
  • Do you put the sub-cas into your servers truststore or not? And why?

Sorry for the lengthy text, but this is a tricky situation I think, and needs to be explained in detail I think. Additionaly, I think rfc 5246 is fuzzy in the aspect how mutual SSL handshake shall be done, exactly.

Rambler
  • 21
  • 1
  • I don't understand the client dev's 'interpretation': given client-1 issued by sub-1 issued by root-1, client-1 is the sender's cert and must be first in the list; sub-1 'directly certif[ies]' client-1 and must be second; root-1 'directly certif[ies]' sub-1 and must be third except that it is the root and 'MAY be omitted'. How does this lead to an interpretation 'there MUST not be a certificate following [client-1]'? ... – dave_thompson_085 Mar 31 '17 at 01:35
  • ... More substantively, yes if the server trusts root-1 there is some risk an adversary could forge sub-2 and use it to forge client-x (and y etc) -- but if the server instead trusts sub-1 there is at least an equal risk the adversary can forge client-x, and probably a substantially higher risk because usually root CA keys can be better protected than 'line' CA keys. – dave_thompson_085 Mar 31 '17 at 01:38
  • Regarding the RFC: usually if you MUST do s.th., the RFC states that clearly. But it says: "Each following certificate MUST directly certify the one preceding it." One could interprete it as, if no certificate follows, the rule does not apply. There is not a sentence like "the client has to send the whole trustchain except of the root-ca." In most of the tutorials and papers I can only see like "the client sends the certificate" - not the certificate chain. I think that's why they implemented it the way that the server must request the issuing ca directly and client sends the cert only. – Rambler Mar 31 '17 at 09:29

2 Answers2

2

They say it seems like the server will then validate the client certificate against the trustchain the client has sent by itself.

Proper certificate validation is never fully based on the certificates sent by the peer but always involves a local trust anchor. This is true for both client and server certificates.

Thus there are following possibilities:

  • Server sends root-1 as accepted CA: client sends client-1 and also sub-1 so that the server can create a trust path to the locally trusted root-1.
  • Server sends sub-1 as accepted CA: client sends client-1 and server creates a trust path using the locally known sub-1 to the locally trusted root-1.
  • If the server sends both sub-1 and root-1 as trusted the client might send either client-1 or client-1 combined with sub-1.

The important thing in all these cases is that the end of the trust chain is always a locally trusted certificate. If the client also sends root-1 this certificate will usually simply be ignored but some implementations might also throw an error since the client is not supposed to send the root certificate.

RoraΖ
  • 12,317
  • 4
  • 51
  • 83
Steffen Ullrich
  • 184,332
  • 29
  • 363
  • 424
  • Thank you, I totally agree with that. But what be the advantages of the first variation? I would assume that the second or third variation is more secure. At least if there were security flaws in certain algorithms where it is possible to create a valid sub-ca based on a root-ca without having the private key. Afaik there have been such security flaws in the past. And if that happens, the only possibility to defend against such rogue sub-cas would be to add the valid sub-cas to the server's truststore again. I just don't get the advantages of only adding the root-ca. – Rambler Mar 31 '17 at 09:12
  • @Rambler: if the server expects all client certificates signed by sub-1 than an attacker must get to the private key of sub-1. If the server instead trusts any certificates directly or indirectly issued by root-1 than the attacker might make use of the private keys of any sub-x signed by root-1, by root-1 itself, might use weak signatures to create a CA matching an existing signature or might try to trick any of the other sub-x outside sub-1 to issue a new certificate which then gets trusted. – Steffen Ullrich Mar 31 '17 at 09:24
0

Consider that even if the server lists root-1 and sub-1 as trusted DNs, a client who has a certificate client-2 issued by sub-2 (signed by root-1) can still authenticate by sending a certificate chain containing client-2 + sub-2. In this case, the server will be able to build a certificate chain anchored by root-1 in its trust store.

The effect of not having intermediate certificates in the trust store is that clients must be configured to have the correct certificate chain in their key store. That is not really a security issue.

It should be equally difficult for an attacker to generate a client-eve apparently signed by sub-1 as to generate a sub-eve apparently signed by root-1. This is of course providing that both root-1 and sub-1 are sufficiently strong and not using known weak or broken algorithms. In the case where they do manage to make a working sub-eve, you will need to revoke root-1.

I don't think the wording in the RFC is relevant to your security concerns. The point of it is to make sure the certificates in the certificate chain are in a well defined order.

notacat
  • 101