Friday 25 January 2019

Securing Windows RDP Connections with a Signed SSL Certificate

Securing Windows RDP Connections with a Signed SSL Certificate


This post captures the steps to get Server 2016 to use a signed SSL certificate for RDP connections. I'd been banging my head against a wall on this for a while but finally figured out what I was doing wrong.

Grab openssl here:
https://slproweb.com/products/Win32OpenSSL.html
I'm using my Lab DC as a Certificate Authority. In the customer site they have a separate CA so I use OpenSSL to generate a Certificate Request (CSR) and submit it to them. Nothing special, you can edit the default windows CA template to set particular values but I found the default web server template works fine. Sometimes you won't have direct access to it.

I installed OpenSSL into c:\OpenSSL normally, rather than Program Files as it's easier to find using the command line afterwards to issue commands against.
If you can't find the openssl.cfg file in the bin subdirectory, install the full version (developer) somewhere temporary and copy it over. The smaller 3Mb version should have everything else you need.
Copy and then edit openssl.cfg (i.e. keep a backup!!). You can make life easier if generating several certificates by updating the defaults:

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = IE
countryName_min = 2
countryName_max = 2

stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Leinster

localityName = Locality Name (eg, city)
localityName_default = Dublin

0.organizationName = Organization Name (eg, company)
0.organizationName_default = Lab

organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = IT

This allows you to hit enter five times when you invoke openssl. You may need / be required to use Subject Alt Names in your request. To do this update the [v3_req] section and add a new one [alt_names] below is as shown.

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = labdc.lab.local

If more than one SAN is needed update as follows:

[alt_names]
DNS.1 = labdc.lab.local
DNS.2 = 192.168.1.10
DNS.3 = labdc

Now open an administrative command prompt and switch to the c:\OpenSSL-Win64\bin directory

execute this command and replace the FQDN with your own server's name:
openssl req -new -sha256 -nodes -out Labdc.lab.local.csr -newkey rsa:2048 -keyout Labdc.lab.local.key -config openssl.cfg


You should see the defaults in [] brackets indicating they are active. Just hit enter until you get to Common Name and paste in the FQDN here. Press enter a few more times until you finish the sequence. You can of course add email and passwords as required.
Now you have two files in the folder:
Labdc.lab.local.csr
Labdc.lab.local.key

Go to your CA and generate the certificate and download it using Base 64 encoding
Labdc.lab.local.cer
You can also download the certificate chain but this isn't required
Labdc.lab.local.p7b

You now can generate a PFX file which contains the Private Key. This is where I went wrong! If you install the Certificate without the private key (Just using the .CER for instance) you can't switch RDP to using it.
openssl pkcs12 -export -out Labdc.lab.local.pfx -inkey Labdc.lab.local.key -in Labdc.lab.local.cer
Labdc.lab.local.pfx

Install this PFX file in the Server's local computer certificate store






The key is to ensure you see the "You have a private key that corresponds to this certificate" here.

Now switch RDP to use this certificate. Open an administrative PowerShell session to get the thumbprint of the cert you want to use:
Get-ChildItem "Cert:\LocalMachine\My"


So in my case it's the first one listed - I've confirmed this by checking against the Certificate Details as shown. Copy the Thumbprint out of the powershell session and use notepad to create the next command replacing the Thumbprint placeholder:
wmic /namespace:\\root\cimv2\TerminalServices PATH Win32_TSGeneralSetting Set SSLCertificateSHA1Hash="5162EC70680B1AF4FF42C697C3168B0F77DA20A9"

Now use the command below to check the current Thumbprint in use:
get-wmiobject -class "Win32_TSGeneralSetting" -namespace root\cimv2\terminalservices -filter "terminalname='RDP-tcp'"


We now run the command prepared in notepad earlier with YOUR Thumbprint (replace mine!!) and set RDP to use it:

Verify with the same command as earlier:

Yep, that looks good. Now disconnect and reconnect with RDP and test that the certificate works. If you use an IP Address it should give you a warning unless that's in your list of SAN entries too, if you use the correct FQDN you should no longer get a warning if the local PC you're using trusts the RootCA.
If the Root CA isn't trusted of course, add it in! When you open the issued certificate you should see the full chain under the certification path section:
That should do it. Hope this helps someone out. The Private Key is the main reason I ran into problems. Ensure you import this and you're good to go. This was tested on Server 2016 and no animals were harmed during this process.