Enabling SSL Client Certificates in an Azure Cloud Service

Posted on Saturday, April 30, 2016

For a recent project I needed to host a WCF service in an Azure Cloud Service Worker Role.
This WCF service was secured using Client Certficiate authentication.

During a typical SSL handshake, the server will send a list of all trusted Root Certificate Authorities in the ServerHello message.
Based upon this list of Root CA's, the client can then pick a Client Certificate whose Root CA is in the trusted list send by the server.
If a server sends an empty list of trusted Root CA's, a client can then send any CLient Certificate it wants.
On the server the certificate will still be validated, but it can be validated against root CA's that you don't necessarily want to use.

In Windows Server 2012 the default behaviour is to not send the list of trusted Root CA's during the SSL handshake.
Luckily this behaviour can be modified by setting a registry key "SendTrustedIssuerList"
Furthermore, the default Azure Windows Server 2012 image contains a small list of trusted Root CA's.
The list can be extended by adding additional Root CA's to the Windows Certificate Store.

If these changes need to be done on an Azure Cloud Service, these changes also need to be applied after a Cloud Service is re-imaged.
In a Cloud Service, this can be done by adding a Startup Task.

Since the Startup Task also needs to be able to add certificates to the Certificate Store, these certificates should be part of Cloud Service deploy package.
Therefor the certificates must be added to the project as well.
The project would then look something like this:

For the certificates to be added to the deploy package, "Copy to output directory" needs to be set to "Copy always".

In the Startup script, first the Root CA certificates are installed, then the Intermediate certificates and after that the registry is updated.

REM   Install certificates.

FOR %%c in (%~dp0\root\*.cer) DO certutil -addstore root %%c
FOR %%c in (%~dp0\intermediate\*.cer) DO certutil -f -addstore CA %%c

REM   Make sure the server is sending the Trusted Root List.

reg add "HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL" /f /v "SendTrustedIssuerList" /t REG_DWORD /d "1"

In the ServiceDefinition.csdef the Startup Task itself can be defined.
Because the Startup Task needs access to the registry and Certificate Store, it needs to run in an elevated context.

  <Task commandLine="Startup\startup.cmd" executionContext="elevated" taskType="simple">

After deploying this to Azure, during an SSL handshake, a client will always send a certificate based upon the server's trusted Root CA's.

A few additional notes:

Make sure not to add too many Root CA's. During handshake the trusted list can only be 16Kb in size.

Never install Intermediate certificate in Windows Trusted Root CA store. If you do, Windows will only send the Intermediate certificates in the Trusted Root CA list and not the Root CA's.

Disclaimer: Any views or opinions expressed on this blog are my own personal ones and do not represent my employer in any way.