How to optimize c# code which issues certificate in Windows Server 2019

163 views Asked by At

I have a code which generates key pair, generates CSR(PKCS#10) then sends to MSCA, accordingly MSCA issues certificates. This code works fine in Windows Server 2012, it takes few seconds to issue a certificate. However, in Windows Server 2016 or 2019 it takes about 100 seconds. I got logs and noticed that in two places it takes 49 seconds to process:

  1. objPkcs10.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextUser, objPrivateKey, null);
  2. string base64p10 = objEnroll.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64);

How to optimize this code or should I configure somewhere to process it faster like in Windows Server 2012 ?

CODE:

//  Create all the objects that will be required
IX509CertificateRequestPkcs10 objPkcs10 = new CX509CertificateRequestPkcs10Class();
IX509PrivateKey objPrivateKey = new CX509PrivateKeyClass();
CX500DistinguishedName objDN = new CX500DistinguishedNameClass();
CObjectId objECC = new CObjectIdClass();
CObjectId objHASH = new CObjectId();
IX509Enrollment2 objEnroll = new CX509EnrollmentClass();
IX509ExtensionKeyUsage objExtensionKeyUsage = new CX509ExtensionKeyUsageClass();
IX509ExtensionEnhancedKeyUsage objX509ExtensionEnhancedKeyUsage = new CX509ExtensionEnhancedKeyUsageClass();
CObjectIds objObjectIds = new CObjectIdsClass();
CObjectId objObjectId = new CObjectIdClass();

//  Initialize the object ID class for the ECC algorithm
objECC.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_PUBKEY_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "TEST_ALG");
//  Initialize the object ID class for the hashing algorithm
objHASH.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "TEST_ALG_2");
//  Provide provider name and the object id to the private key object
objPrivateKey.ProviderName = "Test Software Key Storage Provider";

objPrivateKey.Algorithm = objECC;
objPrivateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE;
objPrivateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
objPrivateKey.ContainerName = privContName;
objPrivateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG;

//  Create the actual key pair
objPrivateKey.Create();

//  Encode the name in using the Distinguished Name object
objDN.Encode(_SOAPRequest.subject, X500NameFlags.XCN_CERT_NAME_STR_NONE);

//  Initialize the PKCS#10 certificate request object based on the private key.
//  Using the context, indicate that this is a user certificate request and don't provide a template name
objPkcs10.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextUser, objPrivateKey, null);
                
//  The newly created certificate request object will contain some default extensions.
//  Suppress these defaults by setting the SuppressDefaults flag
objPkcs10.SuppressDefaults = true;
objPkcs10.HashAlgorithm = objHASH;

// Key Usage Extension
objExtensionKeyUsage.InitializeEncode(
            CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE |
            CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_NON_REPUDIATION_KEY_USAGE |
            CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE |
            CERTENROLLLib.X509KeyUsageFlags.XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE
        );
objPkcs10.X509Extensions.Add((CX509Extension)objExtensionKeyUsage);

// Enhanced Key Usage Extension
objObjectId.InitializeFromValue("1.3.6.1.5.5.7.3.4"); // OID for Client Authentication usage
objObjectIds.Add(objObjectId);
objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
objPkcs10.X509Extensions.Add((CX509Extension)objX509ExtensionEnhancedKeyUsage);

// SMIME Capabilities - add all supported by the default RSA cryptographic provider
CSmimeCapabilitiesClass smimes = new CSmimeCapabilitiesClass();
smimes.AddAvailableSmimeCapabilities(true);
CX509ExtensionSmimeCapabilitiesClass smimeExt = new CX509ExtensionSmimeCapabilitiesClass();
smimeExt.InitializeEncode(smimes);
objPkcs10.X509Extensions.Add((CX509Extension)smimeExt);

//  Assing the subject name by using the Distinguished Name object initialized above
objPkcs10.Subject = objDN;
objEnroll.InitializeFromRequest(objPkcs10);
string base64p10 = objEnroll.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64);

///////////////////////////SEND REQUEST/////////////////////////////

//Create all the objects that will be required
int iDisposition;
string strCAConfig;
string strDisposition;
CCertConfig objCertConfig = new CCertConfigClass();
CCertRequest objCertRequest = new CCertRequestClass();

// Get CA config from UI
strCAConfig = @"localhost\test-CA";
// Submit the request
iDisposition = objCertRequest.Submit(CR_IN_BASE64 | CR_IN_FORMATANY, base64p10, null, strCAConfig);

// Check the submission status
if (CR_DISP_ISSUED != iDisposition) // Not enrolled
{
    strDisposition = objCertRequest.GetDispositionMessage();
    if (CR_DISP_UNDER_SUBMISSION == iDisposition) // Pending
    {
        return "The submission is pending: " + strDisposition;
    }
    else // Failed
    {
        return "error";
    }
}

// Get the certificate
strCert = objCertRequest.GetCertificate(CR_OUT_BASE64);
0

There are 0 answers