How to use CNG KSP to generate DSA keys using the Legacy CertEnroll API RRS feed

  • Question

  • User-2088305003 posted


    I'm creating an Internet Explorer solution which is capable of generating X509 PKCS10 enrollment requests. My solution makes use of the WebEnabled VBScript functions of the CertEnroll API.

    I've managed to get the newer Cryptography API: Next Generation (CNG) Microsoft Key Storage Provider (KSP) to generate enrollment requests containing RSA and ECDSA Keys of various sizes. I've tried to modify the same method to use DSA keys in the enrollment requests, but I have been unsuccessful in getting this to function as expected.

    According to the MSDN CNG documentation, the KSP should be able to generate DSA keys of sizes 512 to 1024 in 64-bit increments: https://msdn.microsoft.com/en-us/library/windows/desktop/bb931355(v=vs.85).asp

    I have managed to generate DSA keys, but I have been unable to use/access them in the Legacy CertEnroll API. I know that my implementation does indeed create DSA keys for two reasons. Firstly, the key-generation pop-up window appears asking the end-user if they wish to use a password to protect the key-pair being generated. Secondly, the Windows Event Viewer contains entries in the 'Windows Logs > Security' section which confirm DSA keys were generated. The log entries in the event viewer are the same for RSA, ECDSA, and DSA. However, attempting to generate a certificate enrollment request with DSA keys results in an empty enrollment request. In fact, any attempt I make to access DSA keys results in null/blank/empty results.

    My code is based on the sample CertEnroll API code which accomplishes a similar task using Legacy CSPs. I've included a sample excerpt of my code below:

    Dim algObjectId
    Dim X509PrivateKey
    Dim X509CertificateRequestPkcs10
    Dim X500DistinguishedName
    Dim X509Enrollment
    'initialize variables to be blank objects for now.
    Set X509PrivateKey = Enroll.CreateObject("X509Enrollment.CX509PrivateKey")
    Set algObjectId = Enroll.CreateObject("X509Enrollment.CObjectId")
    Set X509CertificateRequestPkcs10 = Enroll.CreateObject("X509Enrollment.CX509CertificateRequestPkcs10")
    Set X500DistinguishedName = Enroll.CreateObject("X509Enrollment.CX500DistinguishedName")
    Set X509Enrollment = Enroll.CreateObject("X509Enrollment.CX509Enrollment")
    'Initialize the algObjectID variable based on Algorithm Name
    Call algObjectId.InitializeFromAlgorithmName(0,0,0,"DSA")
    'Initialize the Provider name, Algorithm, and Length
    X509PrivateKey.ProviderName="Microsoft Software Key Storage Provider"
    X509PrivateKey.Algorithm = algObjectId
    X509PrivateKey.Length = 512
    'Encode the cn (defined elsewhere in code) as an X509DistinguishedName object.
    Call X500DistinguishedName.Encode(cn,XCN_CERT_NAME_STR_NONE)
    'Initialize the Certificate Request from private key. Set the DN of the cert request.
    Call X509CertificateRequestPkcs10.initializeFromPrivateKey(ContextUser,X509PrivateKey,"")
    X509CertificateRequestPkcs10.Subject = X500DistinguishedName
    'Initialize an X509 Enrollment Request from the X509CertificateRequestPkcs10.
    Call X509Enrollment.InitializeFromRequest(X509CertificateRequestPkcs10)
    'Create the request: This is where the keys get generated.
    pkcs10req = X509Enrollment.CreateRequest(CRYPT_STRING_BASE64)
    'The pkcs10req variable is empty only when DSA keys are used for the algorithm

    I'm looking for any help/advice I can get to resolve my issue. I've been stuck on this issue for way too long.

    Tuesday, July 4, 2017 1:41 PM

All replies

  • User-460007017 posted

    Hi _AMA_,

    To further help you about this issue, I am trying to invoke someone experienced to help look into this thread, this may take some time and as soon as we get any result, we will post back. 

    Best Regards,

    Yuk Ding

    Wednesday, July 5, 2017 7:49 AM
  • User959839356 posted

    To Community & Moderators:

    The OP is on a rather brilliant track here, and this thread has been neglected for 8 months.  Let's see some activity here.

    To OP:

    Couple of issues with your script;

    Noticed you're using 512 bit key length, and this is only a problem because the big push right now is for 2048 bit key length.  Additionally, many web service and management providers of various services (i.e. Third Party CA's, S/MIME E-Mail Certificate Providers, Merchant Portal Providers) have been pushing for years for people to upgrade to 2048 bit key length.  Ironically we've been using high key lengths for quite some time now, and are migrating to an even higher key length at this time.

    It's worth noting that higher length keys are still not perfect with 2048 bit having been the highest standard length in use by those that are most experienced in maintaining certificate based security for some time because many other services in past years simply either had compatibility problems, or just weren't compatible with the 4096 bit and higher key lengths, but the computing horsepower's been at a level to support the lengthier keys for some time.  It's also worth noting that the same types of service providers we mentioned are now "reluctantly" (very, very, reluctantly) still providing 1024 bit keys as a last resort because the key length being pushed as the current standard is 2048 bit.

    Our recommendation is to maintain the same key length for all services that are making use of Certificate Based Security.

    On another note; it's certainly worth mentioning that X.509 is still the standard supported by the American National Standards Institute (ANSI), if your X.509 ID/Certificate Name is Registered with ANSI (requires paying a substantial fee to ANSI), having such a registration does entitle your domain and/or X.509 ID name to function as a TLD (Top-Level Domain), while such a registration also secures you and/or your entity's right to the name as the Intellectual Property Owner.  To be clear, some people bring up ICANN when we mention X.509 ID's, so for us to be clear, under International Treaties along with PIPA & CIPA here in the United States; ICANN has no choice except to honor such ownerships for those having registered X.509 ID's.  In other words, if you know you need one, it is money well spent.  If anyone questions the legal aspect of this posting, just remember the next time you pop in a Blu-Ray or DVD, the Anti-Piracy Warning in the beginning will state that those caught "Infringing" are subject to "fines and imprisonment" along with "FBI" & "Interpol" both being mentioned as relevant law enforcement in the warning.  Intellectual Property is Intellectual Property, and Infringement is Infringement... no "but" 's about it.

    It may also be worth noting, it would in theory be possible to modify your script to interact with Internet Explorer to use it as a sort of Local Machine CA server for what we could only term "A Loopback-based CA" so that the Local Machine could self-authenticate to a FQDN without using an Active Directory server.  For those running equipment in a private network and/or private cloud that is non-Windows Domain based, such a function could be incredibly useful if the coding is done well.

    In our situation, our WorkGroup designation for our Windows stations is supported as an intranet node to our Linux-Based domain services; however our workaround is by no means a small undertaking to accomplish, and the type of solution you're offering could easily be made to become a low cost solution.

    We wish you the best, and hope we've provided some positive encouragement to further develop your idea while also encouraging the community to give your post the attention it certainly and rightfully deserves.

    @Yuk Ding; Where is this more experienced person you were talking about 8 months ago?

    ...back to the Community...

    Also worth noting... the URL: https://msdn.microsoft.com/en-us/library/windows/desktop/bb931355(v=vs.85).asp is no longer showing up.

    Looking forward to seeing activity on this thread in the near future.

    Thursday, May 17, 2018 7:23 AM