From 389 Directory Server
Auto Enrollment - How it works
Background
An application wishing to enroll for a certificate will use COM components to first locate a CA. It will then submit the request to the CA.
Locating the CA
To locate a CA, the application will first query the registry for an implementation of the ICertConfig interface by looking at the registry key HKEY_CLASSES_ROOT\CLSID\{372FCE38-4324-11D0-8810-00A0C903B83C}.
A class implementing ICertConfig, called CCertConfig ships as part of Windows in the certcli.dll file. It will query the Active Directory server for the local machine via the LDAP protocol to look for an entry under the tree "CN=Enrollment Services, CN=Public Key Services, CN=Services, CN=Configuration, DC=...,DC=...". It will attempt to find an entry for an appropriate CA for the type of certificate being requested by looking at the certificateTemplates attribute.
Depending on how the enrollment is initiated, the user may be presented with a choice of candidate Enrollment Services. After selecting one, the hostname is retrieved from the 'dnshostname' attribute. This is the hostname of the Enrollment Service on the network.
If the machine can't connect to the domain controller (for example, because of a network problem) ICertConfig will instead look for a local CA in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc tree of the registry. If a Microsoft CA is installed on this machine, this registry key will hold its location.
Before ICertConfig returns the list of valid certificate enrollment services to the application, it filters the list. Only certificate enrollment services that are associated with a CA in the domain's CTL (see below) are made available.
The application will then query the registry key (HKEY_CLASSES_ROOT\CLSID\{98AFF3F0-5524-11D0-8812-00A0C903B83C})
and get back the COM class implementing the ICertRequest interface. This interface is well documented in the Microsoft SDK. It will then call the Submit method of that class, with the name of the enrollment service found above.
Submitting the certificate request
The implementation of ICertRequest will then query the system for a COM class implementing the ICertRequestD interface.[1]
Specifically, the client in certcli.dll will call a win32 function such as CoGetClassObject with the CA server host name as a parameter. A class factory for objects implementing the ICertRequestD interface is registered by the CoRegisterClassObject() function in the server. Now, when the client calls C++ methods in the ICertRequestD object, the methods actually get run in the server.
Usually, interfaces are written as IDL definitions and the IDL compiler (midl) will generate the necessary stub (for the server) and proxy (for the client) code, some .h header files, and a binary version of the IDL, called the type library (TLB). Any function parameters and return codes for these methods are serialized by the stub code, and transferred over the wire.
In this case, Microsoft generated the proxy code and built it into certcli.dll for use by the client. They built the stub code into their CA product. And kept the IDL file and TLB file private. This means it is difficult to reimplement the necessary stub code for a new server.[2]
Certificate request parameters
The Enrollment Service's Request() function includes the following parameters:
- CA name: (string with CA's name)
- flags: encoding/type of request being submitted (as defined in
ICertRequest::Submit()) (currently, code assumes 0x0102, which means PKCS#10 binary) - serial number:
- request id: (in/out) (if request is pending administrator approval, disposition is set to
CR_DISP_UNDER_SUBMISSION, and the request number is set here. Client will re-request with request ID - attributes: A string with newline-separated 'name:value' pairs (see below)
- request: The certificate request, encoding as specified in Request
The function is supposed to return:
- PKCS#7 cert chain
- certificate
- disposition
- disposition message
See: Microsoft's documentation of ICertRequest::Submit() for additional details.
Attributes
Enrolling clients can supply additional information to be included in the certificate. This can come in the form of attributes. During a domain controller enrollment, we see:
- DomainController: cdc, rmd, ccm
The meanings of these attributes are (to be revised):
- cdc: domain controller + fqdn
- rmd: ca computer + fqdn
- ccm: ca computer + fqdn
(Ideally, the domain controller GUID would have been submitted here, but alas it was not, I had to hunt in LDAP for the right value. This page: http://technet2.microsoft.com/WindowsServer/en/library/d78843f2-f739-4d1f-84ca-f6337f5685d81033.mspx?mfr=true indicates that the GUID is submitted as part of the Subject Alt Name in the PKCS#10 request, but not according to my testing)
Also, in the PKCS#10 request, is a Microsoft extension called "Microsoft Enrollment Cert Type", which is the template name - we can use this to determine what type of certificate the client is requesting.
Once the Enrollment Service receives the request, it will retrieve the 'Security Blanket', which includes the Kerberos credentials. It could [3] then ensure that the user is authorized to approve such certificate requests. Access to the DCOM service as a whole is managed by the RPCSS Service - before AEP even sees the requests.
Next, the system issues the certificate, sets the return values appropriately, including a 'success' disposition, and returns to the caller.
References
- ↑ This interface is not well documented in the Microsoft SDK. However, enough information is in the header files to reconstruct the missing pieces.
- ↑ Ordinarily this approach would also make it difficult for an application developer to know what functions to implement and the calling conventions for those functions. However Microsoft included in the SDK the header file certreqd.h all the necessary information to recreate the original IDL file, and thus also the stub files. Not only did they include the function names and parameter types for
ICertRequestD, but they also included parameter names. Comparing these to the publicly documentedICertRequestinterface, it was quite straightforward to understand how to implement these functions. - ↑ in a future version, we should make sure we evaluate the Certificate Template Access Control list against this security blanket. This would give us greater resolution in applying the ACLs. As it is today, it's all-or-nothing. Anyone able to submit a Certificate request to the proxy can submit all types of requests. The only way to support a distinction would be to install multiple machines with a proxy on each one.
