Security Do browsers use client certificates to authenticate the user, the device, or both?

Most browsers support client certificates for mutual TLS authentication. But what is really being authenticated here, the end user, their device, or both?

One way to find out is to check where browsers look for client certificates. While Firefox manages its own certificate store, Chrome, Edge and Internet Explorer defer certificate management to Windows.

Windows has two types of certificates stores that are relevant in this context, the local machine store and the current user store:

  • The current user store (cert:\CurrentUser\) is local to a user account on the computer, and users have read and write access to their own store.

    Windows considers the current user store part of the user’s profile. In an Active Directory environment, user profiles are often configured to roam so that users can access their files and settings on whatever (domain-joined) computer they log in to.

    Certificates and credentials can roam too to ensure that users can use the same certificates on all their computers. That even applies to certificates that use the (TPM-backed) Platform Crypto Provider for key storage.

    The current user store is therefore a good place to store certificates that identify the user, maybe as part of a multi-factor authentication scheme. But unless you disable credential roaming, the current user store is not not a good place to store device certificates because the same certificate might be used on multiple computers.

  • The local machine store (cert:\LocalMachine\) is local to the computer and is global to all users on the computer. Non-admin users can use certificates from the local machine store, but they can’t add or remove any certificates. Because certificates are local to a machine, they also don’t roam.

    The local machine store is therefore a good place to store any certificates that identify the device/computer, as opposed to the user.

So which of these certificate stores do Chrome, Edge, and Internet Explorer actually use? If they use the local machine store only, then we could conclude that client certificates are meant to be used for device authentication. In contrast, if browsers ignore the local machine store and only consider the current user store, then it seems safe to assume that browsers intend client certificates to be used for user authentication.

Let’s do a little experiment to find out.

Experimenting with mTLS certificate prompting

Most browsers don’t just silently pick a client certificate when requested by a server to do mTLS authentication. Instead, they show a prompt and let us select and confirm which certificate we want to use.

To find out which certificate stores browsers consider, let’s create two certificates, one in each store.

First, let’s create a certificate Sample machine certificate that:

  • is stored in the local machine store,
  • can be used for client authentication ,
  • has its keys stored in the Microsoft Software Key Storage Provider.

To do that using certreq, we need to do the following:

  1. Create an INF file and save it to machine-cert.inf

    [Version]
     Signature = "$Windows NT$"
    
    [Strings]
     szOID_ENHANCED_KEY_USAGE = 2.5.29.37
     szOID_PKIX_KP_CLIENT_AUTH = 1.3.6.1.5.5.7.3.2
    
    [NewRequest]
     RequestType   = Cert
    
     FriendlyName  = "Sample machine certificate"
     Subject       = "CN=Sample machine certificate"
    
     ProviderName  = "Microsoft Software Key Storage Provider"     ; Use CNG, not CryptoApi
     MachineKeySet = true                                          ; Install to machine store
    
     KeyUsage      = CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERT_KEY_ENCIPHERMENT_KEY_USAGE
     KeyLength     = 2048
     KeyAlgorithm  = RSA
     HashAlgorithm = SHA256
     Exportable    = false
    
     NotAfter      = "10/01/2021"
     NotBefore     = "09/01/2021"
    
    [Extensions]
     %szOID_ENHANCED_KEY_USAGE% = {text}%szOID_PKIX_KP_CLIENT_AUTH%  ; Enable client authentication
    
  2. Run certreq.exe -new .\machine-cert.inf machine-cert.csr

The command also emits a certificate signing request (machine-cert.csr), but we don’t need that.

Now let’s create another certificate, Sample user certificate that is just like the previous one, but stored in the current user’s certificate store:

  1. Create an INF file and save it to user-cert.inf

    [Version]
     Signature = "$Windows NT$"
    
    [Strings]
     szOID_ENHANCED_KEY_USAGE = 2.5.29.37
     szOID_PKIX_KP_CLIENT_AUTH = 1.3.6.1.5.5.7.3.2
    
    [NewRequest]
     RequestType   = Cert
    
     FriendlyName  = "Sample user certificate"
     Subject       = "CN=Sample user certificate"
    
     ProviderName  = "Microsoft Software Key Storage Provider"     ; Use CNG, not CryptoApi
     MachineKeySet = false                                         ; Install to user store
    
     KeyUsage      = CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERT_KEY_ENCIPHERMENT_KEY_USAGE
     KeyLength     = 2048
     KeyAlgorithm  = RSA
     HashAlgorithm = SHA256
     Exportable    = false
    
     NotAfter      = "10/01/2021"
     NotBefore     = "09/01/2021"
    
    [Extensions]
     %szOID_ENHANCED_KEY_USAGE% = {text}%szOID_PKIX_KP_CLIENT_AUTH%  ; Enable client authentication
    
  2. Run certreq.exe -new .\user-cert.inf user-cert.csr

We also need a website that requires mTLS. For that, we can use https://prod.idrix.eu/secure/, a test site run by the people behind VeryCrypt.

First, let’s open the website in Chrome:

Chrome certificate dialog

We might expect Chrome to show two certificates, the one from the user store and the one from the local machine store. But that’s not what’s happening! Instead, Chrome only offers us a single certificate, the user certificate from the current user’s store.

Let’s see if the the (Chrome-based) Edge behaves any differently:

Edge certificate dialog

Again, only the user certificate is shown.

But what about Internet Explorer? Again, same story:

IE11 certificate dialog

There’s a pattern here. And deeply buried in the Microsoft docs, we can find a hint indicating that this behavior is by design:

Client applications such as Internet Explorer normally use the My store of the current user while servers such as Internet Information Services (IIS) use the system My store of the local computer.

For Chrome, I wasn’t able to find any documentation indicating whether or not this behavior is by design. But if we look at the Chromium sources, we can see that it’s calling CertOpenSystemStore which is clearly documented as:

Only current user certificates are accessible using this method, not the local machine store.

Takeaway

Chrome, Edge, and Internet Explorer all consider the current user’s certificate store to be the sole source for certificates, and ignore any certificates in the local machine certificate store. But certificates in the current user’s certificate stores (potentially) roam and are therefore not really suitable for identifying a device. Using mTLS client authentication in browsers is therefore suitable for user authentication, but it’s hardly a good choice for authenticating a device.

Any opinions expressed on this blog are Johannes' own. Refer to the respective vendor’s product documentation for authoritative information.
« Back to home