Tag Archives: Certificate Services

Certificate Services operations fail with error 0x80070057

While implementing a two-tier PKI I ran into the issue that certutil.exe -crl, and PowerShell cmdlets such as Get-CACrlDistributionPoint would fail on the Subordinate Domain CA with a generic error which made finding a solution very difficult:

PS C:\Windows\system32> Get-CACrlDistributionPoint
Get-CACrlDistributionPoint : CCertAdmin::GetConfigEntry: The parameter is incorrect. 0x80070057 (WIN32:
ERROR_INVALID_PARAMETER)
At line:1 char:1
+ Get-CACrlDistributionPoint
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-CACrlDistributionPoint], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.CertificateServices.Administration.Comm
DistributionPointCommand

PS C:\Windows\system32> certutil -crl
CertUtil: -CRL command FAILED: 0x80070057 (WIN32: 87 ERROR_INVALID_PARAMETER)
CertUtil: The parameter is incorrect.
PS C:\Windows\system32>

I had started off by following this guide on Technet Blogs:
http://blogs.technet.com/b/yungchou/archive/2013/10/21/enterprise-pki-with-windows-server-2012-r2-active-directory-certificate-services-part-1-of-2.aspx

Not long after proceeding I realised that I needed to alter certain aspects of the way it was configured. I started again and continued to use the same CA server hostnames but with new CA names, this time preferring to follow this guide by Derek Seaman:
http://www.derekseaman.com/2014/01/windows-server-2012-r2-two-tier-pki-ca-pt-1.html

However I encountered the errors with the subordinate CA refusing to run the PowerShell cmdlets relating to the Certificate Authority. The errors were also encountered by commenter “Per” on Derek’s blog post, and similarly reported in the comments on the Windows Server 2012 R2 Active Directory Certificate Services Microsoft Test Lab page:
http://technet.microsoft.com/en-us/library/hh831348.aspx

There is a Microsoft KB referencing the same error at the time of creating the subordinate CA. The article implicates permissions, however this is a red herring.

It took a lot of trial and error, but eventually I did resolve this issue thanks to some pointers in a Microsoft Directory Services Team Blog post on troubleshooting Certificate Enrollment. I determined the root cause – several superfluous entries in Active Directory for an aborted CA installation. I needed to delete these with ADSIEdit, though I have subsequently discovered that you can also use the AD Sites and Services MMC snap-in to do this (at parent, View > Show Services Node). When I first attempted to set up the CAs I had been using the standard auto-generated names because I had thought that not doing so might invite trouble later on – so my subordinate domain CA had published itself to Active Directory at CN=Enrollment Services,CN=Public Key Services,CN=Services using the name domain-HOSTNAME-CA.

I had thought this entry was sane when I was looking back over the ADSIEdit output while investigating the problem – because I know it formats the cert request using this notation. Then I remembered that I had not used this CA name in my subsequent CA installation attempt. I removed this old name entry from Active Directory and it immediately fixed the issue. I guess because although it was for a different CA installation attempt, crucially it shared the same server hostname, hence the problem when PowerShell was invoking Certificate Services to query the Directory Service.

Following this, I then pruned similar superfluous records for the same abortive CA installation attempt which were located at:
CN=KRA,CN=Public Key Services,CN=Services
CN=AIA,CN=Public Key Services,CN=Services
CN=MY_CA_HOSTNAME,CN=CDP,CN=Public Key Services,CN=Services

Advertisements

Secure Active Directory authentication for non-domain DMZ web sites using LDAPS

Being able to have people log into websites using credentials they already use is a huge advantage. Hosting those websites in DMZ zones away from domain controllers means that you need to do this via LDAP, but this isn’t secure since the query results are sent in plain text. Enter LDAPS, which from the research I did online seems to be the most misunderstood technology I have used to date, with very few documented examples.

It’s a pretty simple idea – wrap LDAP in a TLS session. The LDAP client connects to the server. The server sends over its certificate, which is used to authenticate it as being the actual server the client expects. This is critical since the webserver is delegating authentication to it. A TLS session is established, and the client binds to the directory with credentials sent in plain text, but TLS provides the security against eavesdropping.

What is absolutely baffling is how many big companies are completely oblivious to getting this working correctly. I deal with one of the big players in the email scanning space which offers LDAPS authentication so customers can use their normal Active Directory credentials to check their spam. I had bought a £500 VeriSign certificate expressly for this purpose, but when this certificate expired I discovered that this company still had connectivity to the domain controller. They are clearly not even checking the chain of trust on the certificate, even though they allow it to authenticate users! It would be relatively trivial to exploit this to impersonate a particular domain controller, insert an appropriate dummy user account, and hack any of their customers who use federated authentication. Security by DNS is not security (think man-in-the-middle, or cache-poisoning).

I have also worked with a supposedly major website CMS system which cannot get this right, despite claims by the vendor that it supports LDAPS. It categorically doesn’t – LDAP on a different TCP port is still LDAP.

Concept summary

There seems to be a lot of conflicting information out there on how this works and how the certificates are involved, so this is the overview as I understand it:

  • The LDAPS client initiates a connection to the DC on TCP636 specifiying the DC’s FQDN (IP address or hostname only are not sufficient).
  • The DC checks through its Local Computer certificate store for a certificate with the same FQDN, then signs using its private key as proof of ID. The certificate is sent to the client, so the client gets the DC’s public key.
  • The LDAPS client checks the chain of trust on that certificate. If the CA is not a trusted public one (like VeriSign) the client system will need to have the issuing CA’s own certificate pre-loaded into its Local Computer Trusted Root Certification Authorities certificate store. Remember, the web server is not in the Active Directory domain so it won’t implicity trust that CA.
  • Once the client trusts that the DC is genuine, the SSL session is established and the client can bind to the directory using plain text Active Directory account credentials.
 

Configuring your Domain Controller for LDAPS

This knowledgebase article outlines the steps the DC goes through to select a certificate, and includes details of how to create the CSR for external certification authorites: http://support.microsoft.com/kb/321051

The information there is pretty good, and there aren’t many gotchas. If you’re aiming for third party servers to bind to your AD then you will probably want an SSL certificate from a commercial CA. Be aware that you will need a certificate with a Subject Alternate Name (to have two hostnames registered) if you use a different internal FQDN for that server. The cheap public CAs like GoDaddy could not offer this the last time I enquired (admittedly about two years ago). If the website that will be binding to your directory is your own then you won’t want to buy a certificate. If you don’t already have it, install the Active Directory Certificate Services role to one of your Windows domain servers. That whole process is somewhat outside the scope of this blog post. Heed Microsoft’s warning from their Technet LDAP over SSL wiki:

Warning Before you install a certification authority (CA), you should be aware that you are creating or extending a public key infrastructure (PKI). Be sure to design a PKI that is appropriate for your organization. See PKI Design Brief Overview for additional information.

DCs should auto-enroll for their own certificates once that’s up and running. As per that Microsoft KB article that’s all you need to do. DCs will respond to LDAPS requests providing they can find a valid SSL certificate. I did run into some issues setting up my PKI which I have documented in another post.

If you’re using your own Active Directory domain’s CA, export the CA’s own certificate by running:

certutil -ca.cert c:\temp\domain-SERVERNAME-CA.cer
 

Configuring the DMZ webserver

Assuming your domain controller isn’t in public DNS, add its FQDN to the hosts file on your DMZ webserver.

Use the Certificates MMC snap-in to import the CA’s certificate you exported earlier (run MMC.EXE, File -> Add/Remove Snap-in -> Certificates -> Computer Account -> Local Computer -> Trusted Root Certification Authorities -> Certificates -> right-click -> All Tasks -> Import).

Example C# code snippet for the website:

NetworkCredential networkCredentials = new System.Net.NetworkCredential(adminUsername, adminPassword);

LdapDirectoryIdentifier ldapDirectoryIdentifier = new LdapDirectoryIdentifier(ldapServer, ldapPort);
LdapConnection ldapConnection = new LdapConnection(ldapDirectoryIdentifier, networkCredentials, AuthType.Basic);

ldapConnection.SessionOptions.SecureSocketLayer = true;
ldapConnection.Bind();
 

Verifying your LDAPS server using OpenLDAP

Since in my case I was not developing the .Net code myself, I found it useful to use OpenLDAP to demonstrate to our developers that the server and firewall were definitely working as expected. I had been unable to get the normal Windows LDAP troubleshooting tool LDP.EXE to work and it’s not particularly verbose during failures (as it turns out, I hadn’t been using the FQDN). OpenLDAP is extremely easy to install on any Linux distro with a package management system. I ended up using my Synology NAS at home. The format of the issuing CA certificate needs to be slightly different though (base64 encoded). On the CA server, use:

certutil -ca.cert c:\temp\domain-SERVERNAME-CA.cer
certutil -encode c:\temp\domain-SERVERNAME-CA.cer c:\temp\domain-SERVERNAME-CA.pem
 

Add the following line to OpenLDAP’s ldap.conf (mine was /opt/etc/openldap/ldap.conf):

TLS_CACERT /opt/etc/openldap/domain-SERVERNAME-CA.pem
 

Make sure of course to copy the .pem file to that location.
The ldapsearch syntax is quite a minefield but my sample query was as follows:

ldapsearch -x -v -H 'ldaps://ldap.domain.com' -b 'dc=domain,dc=com' -s base -D 'user@domain.com' -W
 

which binds to the directory as user@domain.com (you are prompted for a password), and requests only the top level directory objects.

It seems to be very difficult to compile OpenLDAP for Windows, in fact it’s actually impossible using MinGW (one of the dependencies CyrusSASL needs Visual Studio to compile).

I tried to use this binary build of OpenLDAP for Windows but it ignores ldap.conf because the people who compiled it forgot to define the variable sysconfdir in the configure script. I was able to use the excellent Process Monitor to track a failed filesystem read to a path featuring the static entry $SYSCONFDIR$ as ldapsearch.exe is invoked. Unfortunately as such you can’t add the CA cert location to the config.