Establishing the PKI Relationship

An important rule in PKI is that the private key can never leave the asset being certified without being protected (and it is best practice that the private key never leaves the asset if possible).  If the private key leaves the certified asset at any time without sufficient protection the key is subject to compromise thus reducing the integrity of the system and the certified asset.  That said, the key pair can only be generated on the asset being certified (a common misconception is that the certification authority (CA) generates the key pair, however this would imply that the CA, a service that is commonly external to the certified asset, could easily impersonate anything it certifies).  This key pair is generated using a cryptographic service provider (CSP), a Dynamic Link Library (DLL) containing functions required to generate and use an asymmetric key pair.  Windows provides a number of  CSPs as part of the operating system installation, however also provides a framework for custom CSP development (https://msdn.microsoft.com/en-us/library/windows/desktop/aa380245(v=vs.85).aspx).  Custom CSPs are rarely used outside of hardware security modules (HSM), a more advanced topic to be covered later.

In most cases key pair generation occurs as part of a certificate request process (without a certificate request the asset can only be self-signed and thus will not be trusted by external entities by default).  As part of the certificate request the requesting user or computer will specify a series of attributes it would like to appear on the certificate.  These attributes can be changed by the certification authority prior to issuance of the certificate (depending on the CA software being used) based on the template, issuance policies, etc.  All of this information is then digitally signed by the new private key to prove ownership and packaged into a ASN.1 DER-encoded certificate request following either Public Key Cryptography Standard (PKCS) #10 (https://www.rsa.com/rsalabs/node.asp?id=2132) a.k.a. RFC 2986 (https://tools.ietf.org/html/rfc2986) or Certificate Management Messages over CMS (CMC) request (https://www.ietf.org/rfc/rfc2797.txt).

Once the request is generated it can be transmitted safely to the certification authority in a number of manners based on the system used and its available capabilities ranging from a completely manual submission to a completely automated enrollment when using Windows Server 2003 or later CA's and domain membership (this topic will be covered in a later post).  Regardless of how the request is transmitted to the CA it will result in a pending certificate request requiring some form of authentication and authorization (which may be automated) and is not governed by the X.509 standard.  In many cases certificates are issued based on templates, a capability defined in RFC 4212 (https://www.ietf.org/rfc/rfc4212.txt).  These templates enable standardization of the format used for a given certificate and, in the case of Microsoft Windows CAs, can be used to determine issuance policies.

At this time, the administrators operating the CA have the ability to review and optionally modify (based on the CA platform used) the request to fit policy.  Once the organization operating the CA has sufficiently determined the authenticity of the request and its authorization the CA administrator can approve the request which will cause the CA to convert the request into an X.509 certificate.  At this time the certificate will contain the public key, a validity period determined by the CA, the location(s) where clients can access the CA's public key (called the Authority Information Access, or AIA), location(s) where revocation information will be published (called the Certificate Revocation List (CRL) Distribution Point, or CDP), a hash of the CA's private key (called the Authority Key Identifier), as well as a number of other parameters that can be optionally configured on the CA (for more information on this please see the previous post in this series, https://blogs.technet.com/b/option_explicit/archive/2012/04/09/pki-series-part-2-certificates-and-the-x.509-standard.aspx).  The authenticity is then established when the CA uses its private key to digitally sign this information thus preventing unauthorized modification.

Using a Microsoft Certification Authority

Microsoft provides many benefits when using the Active Directory Certificate Services (ADCS) certification authority role, especially when configured as an enterprise certification authority.  For the purposes of this post we will limit the discussion of these benefits to only those facilitating enrollment and will not cover topics such as certificate management, template management, or other CA-centric tasks (these will be covered in a later post).

Organizations leveraging an ADCS enterprise CA are able to use features such as certificate auto-enrollment (or for Windows 2000 workstations Automatic Certificate Request) to simplify the process of certificate issuance.  These features allow users and computers to leverage their Active Directory credentials to request certificates from an enterprise CA.

Automatic Certificate Request Settings (ACRS)

Automatic Certificate Request Settings (ACRS) was developed as a means to automatically issue computer certificates on computers running Windows 2000 or later.  This feature enables these computers to automatically enroll themselves for a computer certificate from a specified enterprise CA.

ACRS is configured through computer group policy and will only appear when editing a domain policy (these settings will not be displayed if you are editing your local computer policy) and are at the following location: "Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policies\Automatic Certificate Request".  Certificates used for ACRS must be based on an Active Directory certificate template which is assignable to computer objects (this method cannot be used to enroll user certificates) and can only be based on a v1 template (listed as a "Windows 2000" template in Windows Server 2008 R2 and prior or as schema version 1 on Windows Server 8 beta).

Certificate Auto-Enrollment

Auto-enrollment is an evolution of ACRS that began shipping with Windows 2003.  Auto-enrollment provides both users and computers the ability to participate in automatic certificate enrollment.  Client computers participating in auto-enrollment must use at least Windows 2003 or Windows XP and require an enterprise CA running one of the following operating systems:

  • Windows 2003 Enterprise or Datacenter
  • Windows 2003 R2 Enterprise or Datacenter
  • Windows 2008 Enterprise or Datacenter
  • Windows 2008 R2 Standard, Enterprise, or Datacenter

To use auto-enrollment the user or computer must be allowed both enroll and autoenroll permissions on the Active Directory certificate template.  In addition, the enrolling user or computer must be configured to use auto-enrollment through group policy (note: computer configuration only applies to the computer's automatic enrollment ability and the user's configuration only applies to the user's automaitc enrollment; one does not configure both).

Auto-enrollment requires a certificate template version of at least 2 (listed as "Windows 2003" in Windows 2008 R2 and prior, schema version 2 in Windows Server 8 beta); the autoenroll permission isn't even available on v1 templates.

ADCS Web Enrollment

Microsoft provides Web enrollment as a role feature for ADCS to simplify user certificate enrollment processes (in previous versions users were allowed to enroll certificates on behalf of computers, however this is no longer available).  In its current version (Windows Server 2008+) Web enrollment allows users to request certificates based on v1 and v2 certificate templates and, based upon issuance policies assigned to those templates, can automatically issue certificates based on provided domain authentication.

Certificate Enrollment Web Services (CES) \ Certificate Enrollment Policy Web Services (CEP)

A new feature introduced with Windows Server 2008 R2 is the ability to manage certificate enrollment using Web services using a combination of the Certificate Enrollment Web Services (CES) and Certificate Enrollment Policy Web Services (CEP) role features (under the ADCS role).  These Web services enable administrators to configure client computers to manage certificates without RPC access to the certification authority (a major manageability improvement when dealing with firewalls).  Use of this feature requires at least Windows Vista or Windows Server 2008 certificate clients.

Microsoft Simple Certificate Enrollment Protocol (MSCEP) \ Microsoft Network Device Enrollment Services (NDES)

In order to support Cisco System's Simple Certificate Enrollment Protocol (SCEP) (https://www.cisco.com/warp/public/cc/pd/sqsw/tech/scep_wp.htm) Microsoft provides two different solutions based on what version of Windows is running on the server performing certificate enrollment;  Microsoft Simple Certificate Enrollment Protocol (MSCEP) in Windows Server 2003 (https://www.microsoft.com/download/en/details.aspx?displaylang=en&id=2178) and Network Device Enrollment Services (NDES) role service in Windows Server 2008 (https://technet.microsoft.com/en-us/library/ff955645(v=ws.10).aspx).

Many new devices are requiring certificates to authenticate to corporate resources in order to obtain access to resources such as wireless networks.  Some of these devices have chosen to leverage the SCEP protocol to request their certificate due to its inherent simplicity.  SCEP is essentially a simple Web service that can provide a device a certificate in as few as four exchanges (client requests SCEP server's certificate, SCEP server sends certificate, client requests certificate from SCEP server, server provides certificate) when authentication is not used; Even when the SCEP server requires authentication only a few additional packets are required to complete the transaction.

How to Perform a Certificate Request using the Windows GUI \ CLI

Microsoft Windows offers a number of ways to generate a certificate request.  In addition to the following methods, many applications (such as IIS and Exchange) provide interfaces to request certificates from the operating system to simplify the process and to ensure that all required attributes and OIDs are resident in the request.  To simplify this post, we will cover three of the most common ways to generate certificates; the MMC snap-in, certreq.exe, and Internet Information Services (IIS).

Request a Certificate using the Certificates MMC Snap-In with an Enrollment Policy

If your environment is configured with an enterprise certification authority (or if you are requesting a certificate using Certificat Enrollment Web Service (CES) feature of Windows 2008 R2) you may have the ability to leverage the enrollment policy to handle your certificate request.  Enrollment policies are essentially instructions for how your computer can request certificates from an enterprise certification authority.

  1. Open the Microsoft Management Console (MMC).
  2. Click the File drop-down menu and select "Add / Remove Snap-in...".
  3. Double-click the "Certificates" snap-in and select the principal you want to request a certificate for (the current user, a service account, or the computer's account) and click the "Next >" or "Finish" button.
    1. If you selected service account or computer account choose the user you are requesting a certificate for (you cannot perform any private key management requests for remote computers) and click the "Finish" button.
  4. Click the "OK" button on the "Add or Remove Snap-ins" dialogue.
  5. Expand the newly-added "Certificates" snap-in.
  6. Right-click the "Personal" store (it will appear as a folder), select "All Tasks >", then "Request New Certificate...".
  7. Click the "Next >" button on the "Before You Begin" dialogue.
  8. If you are requesting a certificate based on a published template choose the appropriate enrollment policy and click the "Next" button.  If you need to perform a custom request (i.e. a request where you will need to specify a different enrollment policy than is configured) you can click the "Add New" option under "Custom Request" and specify the enrollment policy server's information.
  9. Choose the template for the certificate you wish to request and click "Enroll".  Note that this screen will only display certificate types that you are allowed to enroll for; selecting the "show all templates" option will display all available templates.
    1. Some certificates will require additional information prior to requesting them.  These can be identified by the caution symbol beneath the template and to the left of to the link to provide the additional information.
  10. Based on the configuration of the certificate template the certificate will either be automatically issued to you or be submitted for authorization by a CA manager.  The certificate will be automatically downloaded and installed once the request is complete if using the Active Directory enrollment policy.  If the certificate was requested using CES from an external organization the certificate can also be installed manually by importing it into the certified entity's personal store.

Request a Certificate using the Certificates MMC Snap-In without an Enrollment Policy (called an offline request)

If you are working with a stand-alone or external certification authority you may need to process your request through submission of a PKCS #10 or CMC request.

  1. Open the Microsoft Management Console (MMC).
  2. Click the File drop-down menu and select "Add / Remove Snap-in...".
  3. Double-click the "Certificates" snap-in and select the principal you want to request a certificate for (the current user, a service account, or the computer's account) and click the "Next >" or "Finish" button.
    1. If you selected service account or computer account choose the user you are requesting a certificate for (you cannot perform any private key management requests for remote computers) and click the "Finish" button.
  4. Click the "OK" button on the "Add or Remove Snap-ins" dialogue.
  5. Expand the newly-added "Certificates" snap-in.
  6. Right-click the "Personal" store (it will appear as a folder), select "All Tasks >", then "Advanced Operations >", then "Create Custom Request...".
  7. Select "Proceed without enrollment policy" under the "Custom Request" header and click the "Next" button.
  8. Choose the template (CNG (not supported on all applications as of this writing) or Legacy Key) from the drop-down menu and the request format (CMC or PKCS #10) and click the "Next" button.
  9. Click the arrow next to "Details" under the "Custom Request" header and click the "Properties" button.
  10. Fill out the certificate properties for the associated request (an explanation of these properties are available in the previous post).  Once complete click the "OK" button.
  11. Click the "Next" button on the "Certificate Information" window.
  12. Choose where you would like to save the resulting request file and the format to save it in and click the "Finish" button.
  13. Provide this file to the certification authority to submit the request (software implementations may vary).
  14. Once the certificate request is approved, the resulting certificate file can be imported into the requesting entity's personal store to join the certificate with its associated private key.

Using certreq.exe

 For those fond of command line interfaces and .inf files Microsoft has provided certreq.exe.  Using certreq.exe is simple, however the associated .inf file can be complex.  Formatting required for the .inf file can be found at the following location: https://technet.microsoft.com/en-us/library/cc736326(v=WS.10).aspx

certreq.exe -new

Generating a new certificate request can be done by running the "certreq.exe -new {requestFileOutputPath}" command and either specifying the requested attributes as switches or providing an .inf file with all of the requested attributes for the new certificate.

certreq.exe -submit

Once a request has been generated it can be easily sent to a CA configured by an enrollment policy using the "certreq.exe -submit {requestFilePath}" switch.

certreq.exe -retrieve

If a certificate has been approved by an enterprise CA it can be retrieved using "certreq.exe -retrieve {requestID}".  This command will retrieve the signed certificate from the CA and allow you to save it to your system.

certreq.exe -accept

To complete a request using certreq.exe you can use the "certreq.exe -accept" switch to install the new certificate and associate it with the private key. 

Using Internet Information Services (IIS)

 A common way to request secure sockets layer (SSL) certificates is through the built-in interfaces provided in IIS.  The following are steps required to perform the certificate request (source: https://technet.microsoft.com/en-us/library/cc732906(v=WS.10).aspx)

  1. Open IIS Manager and navigate to the level you want to manage. For information about opening IIS Manager, see Open IIS Manager (IIS 7). For information about navigating to locations in the UI, see Navigation in IIS Manager (IIS 7).
  2. In Features View, double-click Server Certificates.
  3. In the Actions pane, click Create Certificate Request.
  4. On the Distinguished Name Properties page of the Request Certificate Wizard, type the following information, and then click Next.
    1. In the Common name text box, type a name for the certificate.
    2. In the Organization text box, type the name of the organization in which the certificate will be used.
    3. In the Organizational unit text box, type the name of the organizational unit in the organization in which the certificate will be used.
    4. In the City/locality text box, type the unabbreviated name of the city or locality where your organization or organizational unit is located.
    5. In the State/province text box, type the unabbreviated name of the state or province where your organization or organizational unit is located.
    6. In the Country/region text box, type the name of the country or region where your organization or organizational unit is located.
  5. On the Cryptographic Service Provider Properties page, select either Microsoft RSA SChannel Cryptographic Provider or Microsoft DH SChannel Cryptographic Provider from the Cryptographic service provider drop-down list. By default, IIS 7 uses the Microsoft RSA SChannel Cryptographic Provider.
  6. In the Bit length drop-down list, select a bit length that can be used by the provider. By default, the RSA SChannel provider uses a bit length of 1024. The DH SChannel provider uses a bit length of 512. A longer bit length is more secure, but it can affect performance.
  7. Click Next.
  8. On the File Name page, type a file name in the Specify a file name for the certificate request text box, or click the browse button (…) to locate a file, and then click Finish.
  9. Send the certificate request to a public CA. 

How to Perform a Certificate Request using a Script

For all of the systems administrators wishing to automate this effort somewhat I will provide two script examples on how to request an X.509 certificate, one in VBScript and the other a custom PowerShell cmdlet that I created.  Before getting into the code I will take a moment to cover the object used in requesting certificates, CEnroll (https://msdn.microsoft.com/en-us/library/windows/desktop/aa376007(v=vs.85).aspx).

How to Establish the Relationship Programmatically

Now, for my code monkey readers some sample code thanks to MSDN.  In addition, I will provide a non-developer translation for the sysadmins interested in how things work behind the scenes. 

Generating and Submitting a Certificate Request in C++

The following source code was copied from the following MSDN post  (https://msdn.microsoft.com/en-us/library/windows/desktop/aa387670(v=vs.85).aspx).  Please note that this code uses Windows XP \ Server 2003 R2 and prior methods.

Certificate Request in C++ (and function translation)

Source Code

Non-Developer Translation

// Copyright (C) Microsoft.  All rights reserved

// Example for Certificate Enrollment Control

// used with ICertRequest in C++

//

Standard copyright information

#include <stdio.h>

#include <Certsrv.h> // for ICertRequest object

#include <xenroll.h>

#include <windows.h>

Include all of the necessary DLL's to perform the certificate request.  For those unfamiliar with C++, these .h files are called header files and contain all of the publicly accessible functions in a DLL and the inputs required for them.

HRESULT __cdecl main()

{

This is the beginning of the main function which returns a hexadecimal result code

    // Pointer to interface objects.

    ICEnroll4 * pEnroll = NULL;

    ICertRequest2 * pRequest = NULL;

Here we are defining memory locations where we will place memory pointers for the software interfaces we will use to request the certificate.ICEnroll4 – an interface for enrolling a certificate request (deprecated in Vista \ 2008)ICertRequest2 an interface for requesting a certificate

    // BSTR variables.

    BSTR    bstrDN = NULL;

    BSTR    bstrOID = NULL;

    BSTR    bstrCertAuth = NULL;

    BSTR    bstrReq = NULL;

    BSTR    bstrAttrib = NULL;

Now we are defining the variable inputs we will use later such as: - The distinguished name of the certificate (the subject) - OIDs for the certificate (how it can be used) - A configuration string for the CA it will be submitted to - A string location to hold the resulting PKCS #10 request - A string to hold any attributes the certificate will need

    // Request disposition variable.

    long    nDisp;

…and a location to hold the result code from the request submission attempt

    // Variable for return value.

    HRESULT    hr;

...and finally, a variable to hold result codes in case we encounter any issues.

    // Initialize COM.

    hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );

    // Check status.

    if ( FAILED( hr ) )

    {

        printf("Failed CoInitializeEx - [%x]\n", hr);

        goto error;

    }

Now that all of the variables and interface pointers are defined, we try to initialize the COM interface.CoCreateInstanceEx()

    // Create an instance of the Certificate Enrollment object.

    hr = CoCreateInstance( CLSID_CEnroll,

                           NULL,

                           CLSCTX_INPROC_SERVER,

                           IID_ICEnroll4,

                           (void **)&pEnroll);

    // Check status.

    if ( FAILED( hr ) )

    {

        printf("Failed CoCreateInstance - pEnroll [%x]\n", hr);

        goto error;

    }

Since the COM interface call was successful we use COM to create a new instance of the ICEnroll4 interface at the location we allocatedCoCreateInstance()

    // Create an instance of the Certificate Request object.

    hr = CoCreateInstance( CLSID_CCertRequest,

                           NULL,

                           CLSCTX_INPROC_SERVER,

                           IID_ICertRequest2,

                           (void **)&pRequest);

    // Check status.

    if ( FAILED( hr ) )

    {

        printf("Failed CoCreateInstance - pRequest [%x]\n", hr);

        goto error;

    }

Now we create an instance of the certificate request object and place it into the ICertRequest2 location we allocated before.

    // Create the data for the request.

    // A user interface or database retrieval could

    // be used instead of this sample's hard-coded text.

    bstrDN = SysAllocString(L"CN=UserName"    // Common Name

                            L",OU=UserUnit"   // Org Unit

                            L",O=UserOrg"     // Org

                            L",L=UserCity"    // Locality

                            L",S=WA"          // State

                            L",C=US");        // Country/Region

    if (NULL == bstrDN)

    {

        printf("Failed SysAllocString\n");

        goto error;

    }

Now that we have the memory structures successfully populated with an instance of the interfaces we start building our variables that we will use to perform the request.  Here we are building the distinguished name (a.k.a. subject) of our certificate.  The resulting subject should be “CN=UserName,OU=UserUnit,O=UserOrg,L=UserCity,S=WA,C=US”.  Why use LDAP format?  The X.509 standard was built as part of the X.500 series of directory services standards when it was created.  You may recognize X.500 as a directory services location address; this standard also defined DAP which evolved into LDAP, thus the naming format.

    // Allocate the BSTR representing the certification authority.

    // Note the use of '\\' to produce a single '\' in C++.

    bstrCertAuth = SysAllocString(L"Server\\CertAuth");

    if (NULL == bstrCertAuth)

    {

        printf("Failed SysAllocString\n");

        goto error;

    }

We now set the name of the certification authority we will submit the request to.  In this case it will be “Server\CertAuth”, though requests developed on Windows 7 \ Server 2008 R2 can use a HTTPS location (this is due to the availability of Certificate Enrollment Web Services in Server 2008 R2 (ref: https://blogs.technet.com/b/askds/archive/2010/02/01/certificate-enrollment-web-services.aspx))

    // Allocate the BSTR for the certificate usage.

    bstrOID = SysAllocString(L"1.3.6.1.4.1.311.2.1.21");

    if (NULL == bstrOID)

    {

        printf("Failed SysAllocString\n");

        goto error;

    }

In this section we define the object identifiers (OID) that define the requested use of the certificate we want.  In this case it is “1.3.6.1.4.1.311.2.1.21” which is “SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID”.  Translation: Authenticode Software Publishing  (ref: https://support.microsoft.com/kb/287547)

    // Allocate the BSTR for the attributes.

    // In this case, no attribute is specified.

    bstrAttrib = SysAllocString(L"");

    if (NULL == bstrAttrib)

    {

        printf("Failed SysAllocString\n");

        goto error;

    }

And finally, we define any additional attributes for the certificate (available attributes will be covered later).  In this instance we do not request any additional attributes.

    // Create the PKCS #10.

    hr = pEnroll->createPKCS10( bstrDN, bstrOID, &bstrReq );

    // check status

    if ( FAILED( hr ) )

    {

        printf("Failed createPKCS10 - [%x]\n", hr);

        goto error;

    }

Finally, time to create the request!  Plug the distinguished name and the OID into the createPKCS10 function of the ICEnroll4 interface.  The resulting PKCS10 request is returned to the bstrReq string value we defined in the beginning of the application.createPKCS10

    // Submit the certificate request.

    hr = pRequest->Submit( CR_IN_BASE64 | CR_IN_PKCS10,

                           bstrReq,

                           bstrAttrib,

                           bstrCertAuth,

                           &nDisp );

    // Check status.

    if ( FAILED( hr ) )

    {

        printf("Failed Request Submit - [%x]\n", hr);

        goto error;

    }

    else

        printf("Request submitted; disposition = %d\n", nDisp );

And, now that we have our request built we use the Submit function of the ICertRequest2 function to submit the request to the Server\CertAuth CA.  Note that the format listed for this submission is Base-64 encoded PKCS #10.  The CA will return a result based on the submission’s disposition which is placed in the nDisp variable.  If the submission code comes back successful (a.k.a. less than 0x80000000) we are done!

error:

    // Done processing.

    // Clean up object resources.

    if ( NULL != pEnroll )

        pEnroll->Release();

    if ( NULL != pRequest )

        pRequest->Release();

    // Free BSTR variables.

    if ( NULL != bstrDN )

        SysFreeString ( bstrDN );

    if ( NULL != bstrOID )

        SysFreeString ( bstrOID );

    if ( NULL != bstrCertAuth )

        SysFreeString ( bstrCertAuth );

    if ( NULL != bstrReq )

        SysFreeString ( bstrReq );

    if ( NULL != bstrAttrib )

        SysFreeString ( bstrAttrib );

}

Error handling code, only invoked if things do not go as planned…