Create a Computer Request Including DNS Subject Alternative Name

Applies To: Windows Server 2008

This example demonstrates how to create a computer certificate request that includes the computer Domain Name System (DNS) Name in the Subject Alternative Name extension. If the request is created from the computer context (for example, running as local system), the request should be initialized using ContextMachine. If the request is created from a user account (for example, running as Administrator), the request should be initialized using ContextAdministratorForceMachine.

The requirements for subject name and subject alternative name are dependent on the configuration of certificate templates.

Certificate templates can be configured to enable the subject name to be set automatically by a certification authority (CA) based on the authenticated requester’s Active Directory account. If a certificate template is configured to build the subject name based on Active Directory, values for subject name and subject alternative name should be omitted from the certificate request. If a value is provided, it will not be used.

Certificate templates can also be configured to require that a value for subject name or subject alternative name is included in the certificate request. If a certificate template is configured to require a value for subject name or subject alternative name, a value must be included in the certificate request.

For additional information about configuring certificate templates, see Administering Certificate Templates (https://go.microsoft.com/fwlink/?LinkId=178068).

C#:
CX509CertificateRequestPkcs10Class request = new CX509CertificateRequestPkcs10Class();
request.Initialize( X509CertificateEnrollmentContext.ContextAdministratorForceMachine);


// Build the request altname.
CAlternativeNameClass altname = new CAlternativeNameClass();
altname.InitializeFromString( AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME, DNSName);

CAlternativeNamesClass altnames = new CAlternativeNamesClass();
altnames.Add(altname);

CX509ExtensionAlternativeNamesClass altnameext = new CX509ExtensionAlternativeNamesClass();

altnameext.InitializeEncode(altnames);
request.X509Extensions.Add((CX509Extension)altnameext);
request.PrivateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE;
request.PrivateKey.ProviderName = myProvider;

CObjectId algobj = new CObjectId();
algobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_ANY_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "ECDSA_P521");
request.PrivateKey.Algorithm = algobj;


CObjectId hashobj = new CObjectId();
hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "SHA256");
request.HashAlgorithm = hashobj;

request.Encode();

C++:
BSTR alg = SysAllocString(L"ECDSA_P521");
BSTR hashAlg = SysAllocString(L"SHA256");
IX509CertificateRequestPkcs10* request = NULL;
IObjectId* Algorithm = NULL;
IObjectId* HashObj = NULL;
IAlternativeName* altname = NULL;
IAlternativeNames* altnames = NULL;
IX509ExtensionAlternativeNames* altnameext = NULL;
IX509Extensions* exts = NULL;
IX509PrivateKey *pKey = NULL;
HRESULT hr = S_OK;



hr = CoCreateInstance(
        __uuidof(CX509CertificateRequestPkcs10),
        NULL,       // pUnkOuter
        CLSCTX_INPROC_SERVER,
        __uuidof(IX509CertificateRequestPkcs10),
        (void **) &request);
_JumpIfError(hr, error, _T("CoCreateInstance CX509CertificateRequestPkcs10"));


hr = request->Initialize( ContextAdministratorForceMachine );
_JumpIfError(hr, error, _T("request->Initialize"));


// Build the request altname.
hr = CoCreateInstance(
        __uuidof(CAlternativeName),
        NULL,       // pUnkOuter
        CLSCTX_INPROC_SERVER,
        __uuidof(IAlternativeName),
        (void **) &altname);
_JumpIfError(hr, error, _T("CoCreateInstance CAlternativeName"));

hr = altname->InitializeFromString( XCN_CERT_ALT_NAME_DNS_NAME, DNSName);
_JumpIfError(hr, error, _T("altname->InitializeFromString"));

hr = CoCreateInstance(
        __uuidof(CAlternativeNames),
        NULL,       // pUnkOuter
        CLSCTX_INPROC_SERVER,
        __uuidof(IAlternativeNames),
        (void **) &altnames);
_JumpIfError(hr, error, _T("CoCreateInstance CAlternativeNames"));

hr = altnames->Add(altname);
_JumpIfError(hr, error, _T("altnames->Add"));

hr = CoCreateInstance(
        __uuidof(CX509ExtensionAlternativeNames),
        NULL,       // pUnkOuter
        CLSCTX_INPROC_SERVER,
        __uuidof(IX509ExtensionAlternativeNames),
        (void **) &altnameext);
_JumpIfError(hr, error, _T("CoCreateInstance CX509ExtensionAlternativeNames"));

hr = altnameext->InitializeEncode(altnames);
_JumpIfError(hr, error, _T("altnameext->InitializeEncode"));

hr = request->get_X509Extensions( &exts );
_JumpIfError(hr, error, _T("request->get_X509Extensions"));

hr = exts->Add( altnameext );
_JumpIfError(hr, error, _T("exts->Add"));


hr = request->get_PrivateKey( &pKey );
_JumpIfError(hr, error, _T("request->get_PrivateKey"));

hr = pKey->put_KeySpec( XCN_AT_SIGNATURE );
_JumpIfError(hr, error, _T("pKey->put_KeySpec"));

hr = pKey->put_ProviderName( myProvider );
_JumpIfError(hr, error, _T("pKey->put_ProviderName"));


hr = CoCreateInstance(
        __uuidof(CObjectId),
        NULL,       // pUnkOuter
        CLSCTX_INPROC_SERVER,
        __uuidof(IObjectId),
        (void **) &Algorithm);
_JumpIfError(hr, error, _T("CoCreateInstance CObjectId - Algorithm"));

hr = Algorithm->InitializeFromAlgorithmName(XCN_CRYPT_ANY_GROUP_ID, XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlagsNone, alg);
_JumpIfError(hr, error, _T("Algorithm->InitializeFromAlgorithmName"));


hr = pKey->put_Algorithm( Algorithm );
_JumpIfError(hr, error, _T("pKey->put_Algorithm"));


hr = CoCreateInstance(
        __uuidof(CObjectId),
        NULL,       // pUnkOuter
        CLSCTX_INPROC_SERVER,
        __uuidof(IObjectId),
        (void **) &HashObj);
_JumpIfError(hr, error, _T("CoCreateInstance CObjectId - Hash"));

hr = HashObj->InitializeFromAlgorithmName(XCN_CRYPT_HASH_ALG_OID_GROUP_ID, XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlagsNone, hash);
_JumpIfError(hr, error, _T("HashObj->InitializeFromAlgorithmName"));

hr = request->put_HashAlgorithm( HashObj );
_JumpIfError(hr, error, _T("request->put_HashAlgorithm"));


hr = request->Encode();
_JumpIfError(hr, error, _T("request->Encode"));

goto noerror;

error:
if (NULL != request ) request->Release();

noerror:
if (NULL != Algorithm ) Algorithm->Release();
if (NULL != HashObj ) HashObj->Release();
if (NULL != altname ) altname->Release();
if (NULL != altnames ) altnames->Release();
if (NULL != altnameext ) altnameext->Release();
if (NULL != exts ) exts->Release();
if (NULL != pKey ) pKey->Release();

VBScript:
Dim request, algobj, hashobj, template, altname, altnames, altnameext

Set request = CreateObject( "X509Enrollment.CX509CertificateRequestPkcs10" )
request.Initialize( ContextAdministratorForceMachine )

' Build the request altname.
Set altname = CreateObject( "X509Enrollment.CAlternativeName" )
altname.InitializeFromString XCN_CERT_ALT_NAME_DNS_NAME, DNSName

Set altnames = CreateObject( "X509Enrollment.CAlternativeNames" )
altnames.Add altname

Set altnameext = CreateObject( "X509Enrollment.CX509ExtensionAlternativeNames" )

altnameext.InitializeEncode altnames
request.X509Extensions.Add altnameext

If sign Then
    request.PrivateKey.KeySpec = XCN_AT_SIGNATURE
Else
    request.PrivateKey.KeySpec = XCN_AT_KEYEXCHANGE
End If

request.PrivateKey.ProviderName = myProvider

Set algobj = CreateObject( "X509Enrollment.CObjectId" )
algobj.InitializeFromAlgorithmName XCN_CRYPT_ANY_GROUP_ID, XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlagsNone, "ECDSA_P521"
request.PrivateKey.Algorithm = algobj

Set hashobj = CreateObject( "X509Enrollment.CObjectId" )
hashobj.InitializeFromAlgorithmName XCN_CRYPT_HASH_ALG_OID_GROUP_ID, XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlagsNone, "SHA256"
request.HashAlgorithm = hashobj

request.Encode

VB.NET:
Dim request As New CX509CertificateRequestPkcs10Class
request.Initialize(X509CertificateEnrollmentContext.ContextAdministratorForceMachine)

Dim altname As New CAlternativeNameClass
altname.InitializeFromString(AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME, DNSName)
Dim altnames As New CAlternativeNamesClass
altnames.Add(altname)
Dim altnameext As New CX509ExtensionAlternativeNamesClass
altnameext.InitializeEncode(altnames)
request.X509Extensions.Add(DirectCast(altnameext, CX509Extension))
request.PrivateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE
request.PrivateKey.ProviderName = myProvider

Dim algobj As CObjectId = New CObjectIdClass
algobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_ANY_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "ECDSA_P521")
request.PrivateKey.Algorithm = algobj
Dim hashobj As CObjectId = New CObjectIdClass
hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "SHA256")
request.HashAlgorithm = hashobj
request.Encode()

If the request is dumped, the following extension can be seen in the request.

2.5.29.17: Flags = 0, Length = 17
    Subject Alternative Name
        DNS Name=vistapc.contoso.com

Create a Computer CMC Renewal with an Existing Key

Certificates expire after a period of time and need to be renewed. This example shows how to create a CMC request from an existing computer certificate. The request is created by calling the Encode method.

C#:
// Find an old certificate – this example picks the first in the store
X509Store store = new X509Store("My", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
if (store.Certificates.Count == 0)
{
    Console.WriteLine("No certificate to renew");
    return null;
}
X509Certificate2 cert = store.Certificates[0];

string oldcert = Convert.ToBase64String(cert.RawData);
store.Close();

// Create a request and initialize from old certificate
CX509CertificateRequestCmcClass req = new CX509CertificateRequestCmcClass();
req.InitializeFromCertificate(
        X509CertificateEnrollmentContext.ContextAdministratorForceMachine,
        true,
        oldcert,
        EncodingType.XCN_CRYPT_STRING_BASE64,
        X509RequestInheritOptions.InheritDefault | X509RequestInheritOptions.InheritPrivateKey);

// encode the request
req.Encode();

C++:
IX509CertificateRequestCmc* request = NULL;
HRESULT hr = S_OK;
HCERTSTORE hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY" );
if ( hStore == NULL )
{
_tprintf( _T("CertOpenStore: 0x%x\n"), GetLastError()); goto error; 
}

// Find an old certificate – this example picks the first in the store
PCCERT_CONTEXT pcert = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL );
if ( pcert == NULL )
{
_tprintf( _T("CertFindCertificateInStore: 0x%x\n"), GetLastError()); goto error; 
}

hr = CoCreateInstance(
        __uuidof(CX509CertificateRequestCmc),
        NULL,       // pUnkOuter
        CLSCTX_INPROC_SERVER,
        __uuidof(IX509CertificateRequestCmc),
        (void **) &request);
_JumpIfError(hr, error, _T("CoCreateInstance CX509CertificateRequestCmc"));


BSTR BinCert = SysAllocStringLen( NULL, pcert->cbCertEncoded );
memcpy( BinCert, pcert->pbCertEncoded, pcert->cbCertEncoded );
hr = request->InitializeFromCertificate( ContextAdministratorForceMachine, TRUE, BinCert, XCN_CRYPT_STRING_BINARY, (X509RequestInheritOptions) (InheritDefault | InheritPrivateKey ) );
_JumpIfError(hr, error, _T("request->InitializeFromCertificate"));

hr = request->Encode();
_JumpIfError(hr, error, _T("request->Encode"));

goto noerror;

error:
if (NULL != request ) request->Release();

noerror:
if ( NULL != pcert ) CertFreeCertificateContext(pcert);
if ( NULL != hStore ) CertCloseStore( hStore, 0 );

VBScript:
Dim request, cert, oldcert, store, first

Set store = CreateObject( "CAPICOM.Store")
Store.Open CAPICOM_LOCAL_MACHINE_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY OR CAPICOM_STORE_OPEN_EXISTING_ONLY

first = true
For each cert in Store.Certificates
    If first Then
        oldcert = cert.Export( CAPICOM_ENCODE_BASE64 )
        first = false
    End If
Next

Set request = CreateObject( "X509Enrollment.CX509CertificateRequestPkcs10" )

request.InitializeFromCertificate ContextAdministratorForceMachine, oldcert, XCN_CRYPT_STRING_BASE64, InheritDefault Or InheritPrivateKey
request.Encode

VB.NET:
Dim store As New X509Store("My", StoreLocation.LocalMachine)
store.Open(OpenFlags.ReadOnly)
Dim cert As X509Certificate2 = store.Certificates.Item(0)
Dim req As New CX509CertificateRequestCmcClass
req.InitializeFromCertificate( X509CertificateEnrollmentContext.ContextMachine, Convert.ToBase64String(cert.RawData), EncodingType.XCN_CRYPT_STRING_BASE64, X509RequestInheritOptions.InheritDefault)
store.Close()
req.Encode()