Create a Request with Several Extensions

Applies To: Windows Server 2008

The following code snippet samples show how to add various extensions to a request including Key Usage, Extended/Enhanced Key Usage, Template Name, Version 2 Template, Alternative Name, Basic Constraints, Certificate Policies, Subject Key Identifier, and Secure/Multipurpose Internet Mail Extensions (S/MIME) capabilities.

Key Usage

By default, when the KeyUsage extension is added to the request, it is marked as critical because the Key Usage OID (2.5.25.19") is included in the list of CriticalExtensions collection in the request. Extensions can be removed from the CriticalExtensions collection by calling the Remove method as follows.

C#:
// Remove Key Usage from Critical Extensions collection
for (int i = 0; i < request.CriticalExtensions.Count; i++)
{
    if (request.CriticalExtensions[i].Value == "2.5.29.15")
    {
        request.CriticalExtensions.Remove(i);
        break;
    }
}
CX509ExtensionKeyUsageClass ku = new CX509ExtensionKeyUsageClass();
ku.InitializeEncode( CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE );
ku.Critical = true;
request.X509Extensions.Add((CX509Extension)ku);

VBScript:
' Remove Key Usage from Critical Extensions collection
Dim i
For i = 0 To request.CriticalExtensions.Count
    If request.CriticalExtensions(i).Value = "2.5.29.15" Then
        request.CriticalExtensions.Remove(i)
        Exit For
    End If
Next    
Set ku = CreateObject( "X509Enrollment.CX509ExtensionKeyUsage" )
ku.InitializeEncode XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE
ku.Critical = False
request.X509Extensions.Add ku

VB.NET:
' Remove Key Usage from Critical Extensions collection
Dim I As Integer
For i = 0 To request.CriticalExtensions.Count
    If request.CriticalExtensions(i).Value = "2.5.29.15" Then
        request.CriticalExtensions.Remove(i)
        Exit For
    End If
Next    
Dim ku As New CX509ExtensionKeyUsageClass
ku.InitializeEncode( CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE)
ku.Critical = False
request.X509Extensions.Add(DirectCast(ku, CX509Extension))

Extended/Enhanced Key Usage

 

C#:
CObjectIdClass EkuOid = new CObjectIdClass();
EkuOid.InitializeFromValue( "1.2.3.4.5.6.7.8.9" );
CObjectIdsClass EkuOids = new CObjectIdsClass();
EkuOids.Add(EkuOid);
CX509ExtensionEnhancedKeyUsageClass eku = new CX509ExtensionEnhancedKeyUsageClass();
eku.InitializeEncode( EkuOids );
eku.Critical = false;
request.X509Extensions.Add((CX509Extension)eku);

VBScript:
Set EkuOid = CreateObject( "X509Enrollment.CObjectId" )
EkuOid.InitializeFromValue "1.2.3.4.5.6.7.8.9"
Set EkuOids = CreateObject( "X509Enrollment.CObjectIds" )
EkuOids.Add EkuOid 
Set eku = CreateObject("X509Enrollment.CX509ExtensionEnhancedKeyUsage")
eku.InitializeEncode EkuOids
eku.Critical = False
request.X509Extensions.Add eku

VB.NET:
Dim EkuOid As New CObjectIdClass
EkuOid.InitializeFromValue("1.2.3.4.5.6.7.8.9")
Dim EkuOids As New CObjectIdsClass
EkuOids.Add(EkuOid)
Dim eku As New CX509ExtensionEnhancedKeyUsageClass
eku.InitializeEncode(EkuOids)
eku.Critical = False
request.X509Extensions.Add(DirectCast(eku, CX509Extension))

Version 2 Template

C#:
CObjectIdClass V2TemplateOid = new CObjectIdClass();
V2TemplateOid.InitializeFromValue( "1.3.6.1.4.1.311.21.8.12345.67890.12345.6789012345.67890");
CX509ExtensionTemplateClass V2Template = new CX509ExtensionTemplateClass();
V2Template.InitializeEncode(V2TemplateOid, 101, 0);
request.X509Extensions.Add((CX509Extension)V2Template);

VBScript:
Set V2TemplateOid = CreateObject( "X509Enrollment.CObjectId" )
V2TemplateOid.InitializeFromValue "1.3.6.1.4.1.311.21.8.12345.67890.12345.6789012345.67890"
Set V2Template = CreateObject( "X509Enrollment.CX509ExtensionTemplate")
V2Template.InitializeEncode V2TemplateOid, 101, 0
request.X509Extensions.Add V2Template

VB.NET:
Dim V2TemplateOid As New CObjectIdClass
V2TemplateOid.InitializeFromValue( "1.3.6.1.4.1.311.21.8.12345.67890.12345.6789012345.67890")
Dim V2Template As New CX509ExtensionTemplateClass
V2Template.InitializeEncode(V2TemplateOid, &H65, 0)
request.X509Extensions.Add(DirectCast(V2Template, CX509Extension))

Alternative Name – User Principal Name (UPN)

C#:
CAlternativeNameClass altname = new CAlternativeNameClass();
altname.InitializeFromString(AlternativeNameType.XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME, "upn@domain.com" );
CAlternativeNamesClass altnames = new CAlternativeNamesClass();
altnames.Add(altname);
CX509ExtensionAlternativeNamesClass altnameext = new CX509ExtensionAlternativeNamesClass();
altnameext.InitializeEncode(altnames);
request.X509Extensions.Add((CX509Extension)altnameext);

VBScript:
Set altname = CreateObject( "X509Enrollment.CAlternativeName" )
altname.InitializeFromString XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME, "upn@domain.com"
Set altnames = CreateObject( "X509Enrollment.CAlternativeNames" )
altnames.Add altname
Set altnameext = CreateObject( "X509Enrollment.CX509ExtensionAlternativeNames" )
altnameext.InitializeEncode altnames
request.X509Extensions.Add altnameext

VB.NET::
Dim altname As New CAlternativeNameClass
altname.InitializeFromString( AlternativeNameType.XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME, "upn@domain.com")
Dim altnames As New CAlternativeNamesClass
altnames.Add(altname)
Dim altnameext As New CX509ExtensionAlternativeNamesClass
altnameext.InitializeEncode(altnames)
request.X509Extensions.Add(DirectCast(altnameext, CX509Extension))

Certificate Policies

C#:
CObjectIdClass cpOid = new CObjectIdClass();
cpOid.InitializeFromValue( "2.3.4.5.6.7.8.9.0" );
CCertificatePolicyClass cp = new CCertificatePolicyClass();
CPolicyQualifierClass Qualifier = new CPolicyQualifierClass();
Qualifier.InitializeEncode( "Policy Notice", PolicyQualifierType.PolicyQualifierTypeUserNotice );
cp.Initialize( cpOid );
cp.PolicyQualifiers.Add( Qualifier );
CCertificatePoliciesClass cps = new CCertificatePoliciesClass();
cps.Add( cp );
CX509ExtensionCertificatePoliciesClass cpExt = new CX509ExtensionCertificatePoliciesClass();
cpExt.InitializeEncode( cps );
request.X509Extensions.Add((CX509Extension)cpExt);

VBScript:
Set cpOid = CreateObject( "X509Enrollment.CObjectId" )
cpOid.InitializeFromValue "2.3.4.5.6.7.8.9.0"
Set cp = CreateObject( "X509Enrollment.CCertificatePolicy" )
Set Qualifier = CreateObject( "X509Enrollment.CPolicyQualifier" )
Qualifier.InitializeEncode "Policy Notice", PolicyQualifierTypeUserNotice
cp.Initialize cpOid
cp.PolicyQualifiers.Add Qualifier
Set cps = CreateObject( "X509Enrollment.CCertificatePolicies" )
cps.Add cp
Set cpExt = CreateObject( "X509Enrollment.CX509ExtensionCertificatePolicies" )
cpExt.InitializeEncode cps
request.X509Extensions.Add cpExt

VB.NET:
Dim cpOid As New CObjectIdClass
cpOid.InitializeFromValue("2.3.4.5.6.7.8.9.0")
Dim cp As New CCertificatePolicyClass
Dim Qualifier As New CPolicyQualifierClass
Qualifier.InitializeEncode("Policy Notice", PolicyQualifierType.PolicyQualifierTypeUserNotice)
cp.Initialize(cpOid)
cp.PolicyQualifiers.Add(Qualifier)
Dim cps As New CCertificatePoliciesClass
cps.Add(cp)
Dim cpExt As New CX509ExtensionCertificatePoliciesClass
cpExt.InitializeEncode(cps)
request.X509Extensions.Add(DirectCast(cpExt, CX509Extension))

Subject Key ID

C#:
// Subject Key ID - Create the key pair before doing this as the SKI is derived from the public key.
request.PrivateKey.Create();
CX509ExtensionSubjectKeyIdentifierClass ski = new CX509ExtensionSubjectKeyIdentifierClass();
ski.InitializeEncode(EncodingType.XCN_CRYPT_STRING_BINARY, request.PublicKey.ComputeKeyIdentifier(KeyIdentifierHashAlgorithm.SKIHashSha1, EncodingType.XCN_CRYPT_STRING_BINARY));
request.X509Extensions.Add((CX509Extension)ski);

VBScript:
request.PrivateKey.Create
Dim ski
Set ski = CreateObject( "X509Enrollment.CX509ExtensionSubjectKeyIdentifier" )
ski.InitializeEncode XCN_CRYPT_STRING_BINARY, request.PublicKey.ComputeKeyIdentifier(SKIHashSha1)
request.X509Extensions.Add ski

VB.NET:
request.PrivateKey.Create()
Dim ski As New CX509ExtensionSubjectKeyIdentifierClass
ski.InitializeEncode(EncodingType.XCN_CRYPT_STRING_BINARY, request.PublicKey.ComputeKeyIdentifier(KeyIdentifierHashAlgorithm.SKIHashSha1))
request.X509Extensions.Add(DirectCast(ski, CX509Extension))

S/MIME Capabilities

C#:
// SMIME Capabilities - add all supported by the default RSA cryptographic provider
CSmimeCapabilitiesClass smimes = new CSmimeCapabilitiesClass();
smimes.AddAvailableSmimeCapabilities(false);

CX509ExtensionSmimeCapabilitiesClass smimeExt = new CX509ExtensionSmimeCapabilitiesClass();
smimeExt.InitializeEncode(smimes);
request.X509Extensions.Add((CX509Extension)smimeExt);

VBScript:
Dim smimes
Set smimes = CreateObject( "X509Enrollment.CSmimeCapabilities" )
smimes.AddAvailableSmimeCapabilities( False )

Dim smimeExt
Set smimeExt = CreateObject( "X509Enrollment.CX509ExtensionSmimeCapabilities" )
smimeExt.InitializeEncode smimes
request.X509Extensions.Add smimeExt

VB.NET:
' SMIME Capabilities - add all supported by the default RSA cryptographic provider
Dim smimes As New CSmimeCapabilitiesClass
smimes.AddAvailableSmimeCapabilities(False)
Dim smimeExt As New CX509ExtensionSmimeCapabilitiesClass
smimeExt.InitializeEncode(smimes)
request.X509Extensions.Add(DirectCast(smimeExt, CX509Extension))

Other Attributes

C#:
CX509AttributeOSVersionClass os = new CX509AttributeOSVersionClass();
os.InitializeEncode("9.8.7.6");
CX509AttributesClass attribs = new CX509AttributesClass();
attribs.Add((CX509Attribute)os);
CCryptAttributeClass atty = new CCryptAttributeClass();
atty.InitializeFromValues( attribs );
request.CryptAttributes.Add((CCryptAttribute)atty); 

VBScript:
Set os = CreateObject( "X509Enrollment.CX509AttributeOSVersion" )
os.InitializeEncode "9.8.7.6"
Set attribs = CreateObject( "X509Enrollment.CX509Attributes" )
attribs.Add os
Set atty = CreateObject( "X509Enrollment.CCryptAttribute" )
atty.InitializeFromValues attribs
request.CryptAttributes.Add atty

VB.NET:
Dim os As New CX509AttributeOSVersionClass
os.InitializeEncode("9.8.7.6")
Dim attribs As New CX509AttributesClass
attribs.Add(DirectCast(os, CX509Attribute))
Dim atty As New CCryptAttributeClass
atty.InitializeFromValues(attribs)
request.CryptAttributes.Add(atty)

The previous code adds the following extensions to the request:

Certificate Extensions: 8
    2.5.29.15: Flags = 1(Critical), Length = 4
    Key Usage
        Digital Signature (80)

    2.5.29.37: Flags = 0, Length = c
    Enhanced Key Usage
        Unknown Key Usage (1.2.3.4.5.6.7.8.9)

    1.3.6.1.4.1.311.20.2: Flags = 0, Length = a
    Certificate Template Name (Certificate Type)
        User

    2.5.29.17: Flags = 0, Length = 22
    Subject Alternative Name
        Other Name:
             Principal Name=upn@domain.com

    2.5.29.19: Flags = 1(Critical), Length = 8
    Basic Constraints
        Subject Type=CA
        Path Length Constraint=0

    2.5.29.32: Flags = 0, Length = 3a
    Certificate Policies
        [1]Certificate Policy:
             Policy Identifier=2.3.4.5.6.7.8.9.0
             [1,1]Policy Qualifier Info:
                  Policy Qualifier Id=User Notice
                  Qualifier:
                       Notice Text=Policy Notice

    2.5.29.14: Flags = 0, Length = 16
    Subject Key Identifier
        05 ed d3 b6 7c 84 f1 62 43 01 17 0c 04 e8 d8 61 f4 62 c9 8f

    1.2.840.113549.1.9.15: Flags = 0, Length = 37
    SMIME Capabilities
        [1]SMIME Capability
             Object ID=1.2.840.113549.3.2
             Parameters=02 02 00 80
        [2]SMIME Capability
             Object ID=1.2.840.113549.3.4
             Parameters=02 02 00 80
        [3]SMIME Capability
             Object ID=1.3.14.3.2.7
        [4]SMIME Capability
             Object ID=1.2.840.113549.3.7

Submitting a Request to an Online Enterprise CA

 

 

Figure 4   Advanced Enrollment Process

The following code shows how to submit a request to an Enterprise CA. Depending on the configuration of the requested template, the certificate may be issued immediately or the certificate may require later approval. In cases where a request is not immediately issued, the request identifier should be stored, and then, periodic polling should be used to detect when the request has been issued (or denied). Two functions are defined—the first function is SubmitRequest, which submits the request to a CA and the second function is used to poll for the status when a certificate has not been immediately issued.

C#:
static int SubmitRequest( IX509CertificateRequest req, string CANameStr )
{
    CX509EnrollmentClass enroll = new CX509EnrollmentClass();
    enroll.InitializeFromRequest( req );

    string RequestStr = enroll.CreateRequest( EncodingType.XCN_CRYPT_STRING_BASE64);

    CCertRequestClass CertRequest = new CCertRequestClass();
    int Disposition = CertRequest.Submit( CR_IN_BASE64, RequestStr, "", CANameStr);
    string StatusStr = "";

    string DispStr = CertRequest.GetDispositionMessage();
    if (Disposition != CR_DISP_ISSUED )
    {
        StatusStr = CertRequest.GetErrorMessageText(  CertRequest.GetLastStatus(), 0) + " : " + DispStr;
    }

    switch (Disposition)
    {
        case CR_DISP_DENIED:
            Console.WriteLine("Submit returned CR_DISP_DENIED - status " + StatusStr); 
            return -1;

        case CR_DISP_ERROR:
            Console.WriteLine("Submit returned CR_DISP_ERROR - status " + StatusStr); 
            return -1;

        case CR_DISP_INCOMPLETE:
            Console.WriteLine("Submit returned CR_DISP_INCOMPLETE - status " + StatusStr);
            return -1;

        case CR_DISP_ISSUED:
            string Cert = CertRequest.GetFullResponseProperty(  FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64 ).ToString();
            enroll.InstallResponse( InstallResponseRestrictionFlags.AllowNone, Cert, EncodingType.XCN_CRYPT_STRING_BASE64, "" );
            return 0;

        case CR_DISP_ISSUED_OUT_OF_BAND:
            Console.WriteLine("Submit returned CR_DISP_ISSUED_OUT_OF_BAND - status " + StatusStr);
            return -1;

        case CR_DISP_UNDER_SUBMISSION:
            return CertRequest.GetRequestId();

        default:
            Console.WriteLine("Submit returned " + Disposition + " - status " + StatusStr);
            return -1;

    }
}
static int GetResponse(string CANameStr, int ID, X509CertificateEnrollmentContext context)
{
    CCertRequestClass CertRequest = new CCertRequestClass();

    int Disposition = CertRequest.RetrievePending(ID, CANameStr);
    if (Disposition == CR_DISP_ISSUED)
    {
        CX509EnrollmentClass enroll = new CX509EnrollmentClass();
        string Cert = CertRequest.GetFullResponseProperty(FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64).ToString();
        enroll.Initialize(context);
        enroll.InstallResponse(InstallResponseRestrictionFlags.AllowNone, Cert, EncodingType.XCN_CRYPT_STRING_BASE64, "");
    }

    return Disposition;
}

static void SubmitAndPollRequest(IX509CertificateRequest req, string CANameStr)
{
    int ID = SubmitRequest(req, CANameStr);

    // If the ID is > 0 then the request has not yet been issued - poll for the result.
    while (ID > 0)
    {
        // Wait for a second and then poll to see if the certificate has been issued.
        System.Threading.Thread.Sleep(1000);
        int disp = GetResponse(CANameStr, ID, X509CertificateEnrollmentContext.ContextUser);

        // Sometimes we get a denied during the time when the certificate is being issued.
        if (disp == CR_DISP_DENIED)
        {
            // Wait for a couple of seconds and then poll to see if the certificate has been issued.
            System.Threading.Thread.Sleep(2000);
            disp = GetResponse(CANameStr, ID, X509CertificateEnrollmentContext.ContextUser);
        }

        if (disp == CR_DISP_ISSUED)
        {
            // The certificate was issued.
            break;
        }

        // If the request has really been denied then bail out.
        if (disp == CR_DISP_DENIED)
        {
            //Console.WriteLine("Request Denied");
            break;
        }
    }
}

C++:
long SubmitRequest(IX509CertificateRequest* req, _TCHAR* CANameStr )
{
IX509Enrollment*enroll = NULL;
ICertRequest2*CertRequest = NULL;
BSTRRequestStr = NULL;
BSTRDispStr = NULL;
LONGRequestStatus = 0;
BSTRStatusStr = NULL;
HRESULThr = S_OK;
longID = 0;
VARIANTCert;
Cert.vt = VT_EMPTY;


hr = CoCreateInstance(
            __uuidof(CX509Enrollment),
            NULL,       // pUnkOuter
            CLSCTX_INPROC_SERVER,
            __uuidof(IX509Enrollment),
            (void **) &enroll);
    _JumpIfError(hr, error, _T("CoCreateInstance CX509Enrollment"));

hr = enroll->InitializeFromRequest( req );
    _JumpIfError(hr, error, _T("enroll->InitializeFromRequest"));

hr = enroll->CreateRequest( XCN_CRYPT_STRING_BASE64, &RequestStr );
    _JumpIfError(hr, error, _T("enroll->CreateRequest"));

hr = CoCreateInstance(CLSID_CCertRequest,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_ICertRequest2,
                          (void **)&CertRequest);
    _JumpIfError(hr, error, _T("CoCreateInstance CCertRequest"));

long Disposition = 0;
hr = CertRequest->Submit( CR_IN_BASE64, RequestStr, _T(""), CANameStr, &Disposition );
    _JumpIfError(hr, error, _T("CertRequest->Submit"));

hr = CertRequest->GetDispositionMessage( &DispStr );
    _JumpIfError(hr, error, _T("CertRequest->GetDispositionMessage"));

if (Disposition != CR_DISP_ISSUED )
    {
hr = CertRequest->GetLastStatus( &RequestStatus );
    _JumpIfError(hr, error, _T("CertRequest->GetLastStatus"));

hr = CertRequest->GetErrorMessageText( RequestStatus, 0, &StatusStr );
    _JumpIfError(hr, error, _T("CertRequest->GetErrorMessageText"));
}

if (Disposition == CR_DISP_ISSUED ) 
    {
        hr = CertRequest->GetFullResponseProperty( FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64, &Cert );
    _JumpIfError(hr, error, _T("CertRequest->GetFullResponseProperty"));

hr = enroll->InstallResponse(AllowNone, Cert.bstrVal, XCN_CRYPT_STRING_ANY, _T(""));
    _JumpIfError(hr, error, _T("enroll->InstallResponse"));
    }
    else
    {
        if ( Disposition == CR_DISP_UNDER_SUBMISSION )
        {
hr = CertRequest->GetRequestId( &ID );
    _JumpIfError(hr, error, _T("CertRequest->GetRequestId"));

wprintf( L"Under Submission ID %d\n", ID );
        }
else
{
wprintf( L"CertRequest Submit Failed, Disposition = %d, %s, %s\n", Disposition, DispStr, StatusStr );

ID = -1;
}
    }

error:

SysFreeString(RequestStr);
SysFreeString(DispStr);
SysFreeString(StatusStr);
if ( NULL != enroll ) enroll->Release();
if ( NULL != CertRequest ) CertRequest->Release();
if ( VT_BSTR == Cert.vt ) SysFreeString( Cert.bstrVal );

    return ID;
}



long GetResponse(_TCHAR* CANameStr, long ID, X509CertificateEnrollmentContext context )
{
IX509Enrollment*enroll = NULL;
ICertRequest2*CertRequest = NULL;
HRESULT hr = S_OK;

hr = CoCreateInstance(CLSID_CCertRequest,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_ICertRequest2,
                          (void **)&CertRequest);
    _JumpIfError(hr, error, _T("CoCreateInstance CCertRequest"));

long Disposition;
hr = CertRequest->RetrievePending( ID, CANameStr, &Disposition );
    _JumpIfError(hr, error, _T("CertRequest->RetrievePending"));

if (Disposition == CR_DISP_ISSUED)
{
hr = CoCreateInstance(
__uuidof(CX509Enrollment),
NULL,       // pUnkOuter
CLSCTX_INPROC_SERVER,
__uuidof(IX509Enrollment),
(void **) &enroll);
_JumpIfError(hr, error, _T("CoCreateInstance CX509Enrollment"));

VARIANT Cert;
        hr = CertRequest->GetFullResponseProperty( FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64, &Cert );
    _JumpIfError(hr, error, _T("CertRequest->GetFullResponseProperty"));


hr = enroll->Initialize( context );
_JumpIfError(hr, error, _T("enroll->Initialize"));

hr = enroll->InstallResponse(AllowNone, Cert.bstrVal, XCN_CRYPT_STRING_ANY, _T(""));
    _JumpIfError(hr, error, _T("enroll->InstallResponse"));
}

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

    return Disposition;
}


void SubmitAndPollRequest(IX509CertificateRequest* req, _TCHAR* CANameStr, X509CertificateEnrollmentContext context )
{
int ID = SubmitRequest(req, CANameStr );


// If the ID is > 0 then the request has not yet been issued - poll for the result.
while (ID > 0)
{
// Wait for a second and then poll to see if the certificate has been issued.
Sleep(1000);
int disp = GetResponse( CANameStr, ID, context );

printf( "disp = %d\n", disp );

// Sometimes we get a denied during the time when the certificate is being issued.
if (disp == CR_DISP_DENIED)
{
// Wait for a couple of seconds and then poll to see if the certificate has been issued.
Sleep(2000);
disp = GetResponse(CANameStr, ID, context );
}

if (disp == CR_DISP_ISSUED)
{
// The certificate was issued.
break;
}

// If the request has really been denied then bail out.
if (disp == CR_DISP_DENIED)
{
break;
}
}
}

VBScript:
Sub SubmitAndPollRequest(req, CANameStr, context )
    Dim ID
    Dim disp
    
    ID = SubmitRequest(CANameStr, req )
    While ID > 0
        WScript.Sleep 1000
        disp = GetResponse(CANameStr, ID, context )
        If (disp = CR_DISP_DENIED) Then
            WScript.Sleep 2000
            disp = GetResponse(CANameStr, ID, context )
        End If
        
        If Disp = CR_DISP_ISSUED Or Disp = CR_DISP_DENIED Then
            Exit Sub
        End If
    Wend
End Sub


Function SubmitRequest( CANameStr, Req )
    Dim enrollment    
    Set enrollment = CreateObject( "X509Enrollment.CX509Enrollment" )
    enrollment.InitializeFromRequest Req
    Dim RequestStr
    RequestStr = enrollment.CreateRequest( XCN_CRYPT_STRING_BASE64 )
    Dim CertRequest
    Set CertRequest = CreateObject( "CertificateAuthority.Request" )
    Dim Disposition
    Disposition = CertRequest.Submit( CR_IN_ENCODEANY Or CR_IN_FORMATANY, RequestStr, "", CANameStr )
    Dim DispStr 
    DispStr = CertRequest.GetDispositionMessage()
    Dim StatusStr
    StatusStr = ""
    If Disposition <> CR_DISP_ISSUED Then
        StatusStr = CertRequest.GetErrorMessageText(CertRequest.GetLastStatus(), 0) & " : " & DispStr
    End If
    
    If Disposition = CR_DISP_ISSUED Then
        Dim Cert
    Cert = CertRequest.GetFullResponseProperty( FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64 )
    Call enrollment.InstallResponse( AllowNone, Cert, XCN_CRYPT_STRING_ANY, "" )
    SubmitRequest = 0
    Else
    If Disposition = CR_DISP_UNDER_SUBMISSION Then
        SubmitRequest = CertRequest.GetRequestId
    Else    
        SubmitRequest = -1
        WScript.echo "Submit failed - Disposition = " & Disposition & " Status " & StatusStr
    End If
    End If
End Function



Function GetResponse( CANameStr, ID, context )
    Dim CertRequest
    Set CertRequest = CreateObject( "CertificateAuthority.Request" )
    Dim Disposition
    Disposition = CertRequest.RetrievePending( ID, CANameStr )
    If Disposition = CR_DISP_ISSUED Then
        Dim enrollment
        Set enrollment = CreateObject( "X509Enrollment.CX509Enrollment" )
        Dim Cert
    Cert = CertRequest.GetFullResponseProperty( FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64 )
    enrollment.Initialize context
    enrollment.InstallResponse AllowNone, Cert, XCN_CRYPT_STRING_ANY, ""
   End If

   GetResponse = Disposition
End Function

VB.NET:
Private Shared Function SubmitRequest(ByVal req As IX509CertificateRequest, ByVal CANameStr As String) As Integer
    Dim enroll As New CX509EnrollmentClass
    enroll.InitializeFromRequest(req)
    Dim RequestStr As String = enroll.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64)
    Dim CertRequest As New CCertRequestClass
    Dim Disposition As Integer = CertRequest.Submit(CR_IN_BASE64, RequestStr, "", CANameStr)
    Dim StatusStr As String = ""
    Dim DispStr As String = CertRequest.GetDispositionMessage()
    If Disposition <> CR_DISP_ISSUED Then
        StatusStr = CertRequest.GetErrorMessageText(CertRequest.GetLastStatus(), 0) & " : " & DispStr
    End If
    Select Case Disposition
        Case CR_DISP_ISSUED
            Dim Cert As String = CertRequest.GetFullResponseProperty(FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64).ToString
            enroll.InstallResponse(InstallResponseRestrictionFlags.AllowNone, Cert, EncodingType.XCN_CRYPT_STRING_BASE64, "")
            Return 0
        Case CR_DISP_UNDER_SUBMISSION
            Return CertRequest.GetRequestId
        Case CR_DISP_DENIED
            Console.WriteLine("Submit CR_DISP_DENIED " & StatusStr)
        Case CR_DISP_ERROR
            Console.WriteLine("Submit CR_DISP_DENIED " & StatusStr)
        Case CR_DISP_INCOMPLETE
            Console.WriteLine("Submit CR_DISP_DENIED " & StatusStr)
        Case CR_DISP_ISSUED_OUT_OF_BAND
            Console.WriteLine("Submit CR_DISP_DENIED " & StatusStr)
        Case Else
            Console.WriteLine("Submit Error " & Disposition & " : " & StatusStr)
    End Select
    Return -1
End Function

Private Shared Function GetResponse(ByVal CANameStr As String, ByVal ID As Integer, ByVal context As X509CertificateEnrollmentContext) As Integer
    Dim CertRequest As New CCertRequestClass
    Dim Disposition As Integer = CertRequest.RetrievePending(ID, CANameStr)
    If (Disposition = CR_DISP_ISSUED) Then
        Dim enroll As New CX509EnrollmentClass
        Dim Cert As String = CertRequest.GetFullResponseProperty(FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64).ToString
        enroll.Initialize(context)
        enroll.InstallResponse(InstallResponseRestrictionFlags.AllowNone, Cert, EncodingType.XCN_CRYPT_STRING_BASE64, "")
    End If
    Return Disposition
End Function

Private Shared Sub SubmitAndPollRequest(ByVal req As IX509CertificateRequest, ByVal CANameStr As String, ByVal context As X509CertificateEnrollmentContext)
    Dim ID As Integer
    Dim disp As Integer
    ID = SubmitRequest(req, CANameStr)

    ' If the ID is > 0 then the request has not yet been issued - poll for the result.
    While ID > 0
        System.Threading.Thread.Sleep(1000)
        disp = GetResponse(CANameStr, ID, X509CertificateEnrollmentContext.ContextUser)

        ' Sometimes we get a denied during the time when the certificate is being issued.
        If (disp = CR_DISP_DENIED) Then
            ' Wait for a couple of seconds and then poll to see if the certificate has been issued.
            System.Threading.Thread.Sleep(2000)
            disp = GetResponse(CANameStr, ID, X509CertificateEnrollmentContext.ContextUser)
        End If

        If disp = CR_DISP_ISSUED Then
            Exit While
        End If

        If disp = CR_DISP_DENIED Then
            Exit While
        End If
    End While
End Sub