One of the common questions I’ve seen asked lately is related to TLS client authentication, which likely means more people are interested in stronger client authentication. The problem people are hitting is described in KB 933430, where the message the server sends to the client to request client authentication is being trimmed. Let’s look at why this occurs and what are the possible solutions, but first some background.
When TLS server is configured to ask for client authentication, it sends as part of the handshake the TLS CertificateRequest message. The TLS 1.2 RFC defines the message as follows:
struct { ClientCertificateType certificate_types<1..2^8-1>; SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>; DistinguishedName certificate_authorities<0..2^16-1>; } CertificateRequest;
where the supported_signature_algorithms is addition in the 1.2 version of the TLS protocol. The certificate_authorities part of the message is further defined:
opaque DistinguishedName<1..2^16-1>;
When the server sends this message, it optionally fills in the certificate_authorities part of the message with a list of distinguished names of acceptable CAs on the server. The main reason for this list is for the server to help the client in narrowing down the set of acceptable certificates to choose from. For example, if the server only accepts certificates issued by the company private CA, there is no need for the client to send a certificate issued by a public CA, as the server won’t trust it. Nothing in the RFC prevents the client from sending any certificate, but it is in the best interest of the client to send appropriate certificate.
On Windows, the way the TLS is implemented, the server picks all the certificates that are present in the “Local Computer” “Trusted Root Certification Authorities” store (or in short the local machine root store). With Windows Server 2008 and later, the default list of trusted authorities is very small as I’ve described in a previous post, so including those distinguished names in the message does not pose a problem. However, if the server has most of the trusted roots installed or has additional root certificates, it is possible for the combined length of the distinguished names to exceed the limit of the TLS record size, which is 214 (16384) bytes. The TLS standard supports this, as it breaks messages up into records and a single message can span multiple records - this is called record fragmentation. Windows does not implement this part of the RFC though, so it cannot send messages that are bigger than what a TLS record can hold. In most cases this works just fine, but in this particular instance it is a problem.
Now, what can be done to solve this problem. The are two solutions - either decrease the list of root certificates in the message or do not send that list at all (allowed by the RFC). The former approach is possible, but is more error prone and I wouldn’t recommend it for most people. I would argue that the latter approach is the preferred one, but I always get backlash when I propose this. If one were to think about the original purpose of this message and the way Windows has implemented this, it will be easier to understand why this is better. Remember:
- the server wants to “help” the client do an informed decision on which certificate to send as its identity
- Windows sends the contents of the local machine root store as the list
If we take those two factors together, the end result is that the server is not helping *at all* the client to make a good decision. A few sources - my own research, ssllabs.com’s SSL Survey, and the EFF SSL Observatory - point out that 10-15 root CAs issue the majority of the certificates seen on the web, therefore if we send 16k worth of these, the probability that any certificate the client has is *not* issued by someone in the list is close to zero. Therefore, in this configuration, the list the server presents to the client doesn’t effectively filter down the set of certificates on the client. It is almost equivalent to sending an empty list to the client and ask it to chose randomly.
In short, if you are hitting this problem, you are better of using Method 3 described in KB 933430 and setting SendTrustedIssuerList to 0, which disables sending of the list of CAs than any other method.