Decrypt my World

Cryptography, Security, Debugging and more!

How to request an smartcard logon cert programmatically (C#)

How to request an smartcard logon cert programmatically (C#)

  • Comments 3

Hi all,

The other day I created this C# sample which shows how to request an smartcard logon cert to a CA. It is based on this other sample: How to create a certificate request with CertEnroll and .NET (C#).

using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

// Add the CertEnroll namespace
using CERTENROLLLib;
using CERTCLIENTLib;

namespace CATest
{
public partial class Form1 : Form
{
private const int CC_DEFAULTCONFIG = 0;
private const int CC_UIPICKCONFIG = 0x1;
private const int CR_IN_BASE64 = 0x1;
private const int CR_IN_FORMATANY = 0;
private const int CR_IN_PKCS10 = 0x100;
private const int CR_DISP_ISSUED = 0x3;
private const int CR_DISP_UNDER_SUBMISSION = 0x5;
private const int CR_OUT_BASE64 = 0x1;
private const int CR_OUT_CHAIN = 0x100;

public Form1()
{
InitializeComponent();
}

// Create request
private void createRequestButton_Click(object sender, EventArgs e)
{
// Create all the objects that will be required
CX509CertificateRequestPkcs10 objPkcs10 = new CX509CertificateRequestPkcs10Class();
CX509PrivateKey objPrivateKey = new CX509PrivateKeyClass();
CCspInformations objCSPs = new CCspInformationsClass();
CX500DistinguishedName objDN = new CX500DistinguishedNameClass();
CX509Enrollment objEnroll = new CX509EnrollmentClass();
CObjectIds objObjectIds = new CObjectIdsClass();
CObjectId objObjectId = new CObjectIdClass();
CX509ExtensionKeyUsage objExtensionKeyUsage = new CX509ExtensionKeyUsageClass();
CX509ExtensionEnhancedKeyUsage objX509ExtensionEnhancedKeyUsage = new CX509ExtensionEnhancedKeyUsageClass();
CX509ExtensionTemplateName objExtensionTemplate = new CX509ExtensionTemplateName();
string strRequest;

try
{
requestText.Text = "";

// Get all available CSPs
objCSPs.AddAvailableCsps();

// Provide key info
objPrivateKey.ContainerName = "Alex";
objPrivateKey.ProviderName = "eToken Base Cryptographic Provider";
objPrivateKey.ProviderType = X509ProviderType.XCN_PROV_RSA_FULL;
objPrivateKey.Length = 1024;
objPrivateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
objPrivateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_ALL_USAGES;
objPrivateKey.MachineContext = false;
objPrivateKey.CspInformations = objCSPs;

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

// 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,
""
);

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

// Enhanced Key Usage Extension
objObjectId.InitializeFromValue("1.3.6.1.4.1.311.20.2.2"); // OID for Smartcard logon
objObjectIds.Add(objObjectId);
objX509ExtensionEnhancedKeyUsage.InitializeEncode(objObjectIds);
objPkcs10.X509Extensions.Add((CX509Extension)objX509ExtensionEnhancedKeyUsage);

// Template Extension
objExtensionTemplate.InitializeEncode("SmartcardLogon");
objPkcs10.X509Extensions.Add((CX509Extension)objExtensionTemplate);

// Encode the name in using the Distinguished Name object
objDN.Encode(
"CN=AlejaCMa",
X500NameFlags.XCN_CERT_NAME_STR_NONE
);

// Assing the subject name by using the Distinguished Name object initialized above
objPkcs10.Subject = objDN;

// Create enrollment request
objEnroll.InitializeFromRequest(objPkcs10);
strRequest = objEnroll.CreateRequest(
EncodingType.XCN_CRYPT_STRING_BASE64
);

requestText.Text = strRequest;

} catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

// Submit request to CA and get response
private void sendRequestButton_Click(object sender, EventArgs e)
{
// Create all the objects that will be required
CCertConfig objCertConfig = new CCertConfigClass();
CCertRequest objCertRequest = new CCertRequestClass();
string strCAConfig;
string strRequest;
int iDisposition;
string strDisposition;
string strCert;

try
{
strRequest = requestText.Text;

// Get CA config from UI
//strCAConfig = objCertConfig.GetConfig(CC_DEFAULTCONFIG);
strCAConfig = objCertConfig.GetConfig(CC_UIPICKCONFIG);

// Submit the request
iDisposition = objCertRequest.Submit(
CR_IN_BASE64 | CR_IN_FORMATANY,
strRequest,
null,
strCAConfig
);

// Check the submission status
if (CR_DISP_ISSUED != iDisposition) // Not enrolled
{
strDisposition = objCertRequest.GetDispositionMessage();

if (CR_DISP_UNDER_SUBMISSION == iDisposition) // Pending
{
MessageBox.Show("The submission is pending: " + strDisposition);
return;
}
else // Failed
{
MessageBox.Show("The submission failed: " + strDisposition);
MessageBox.Show("Last status: " + objCertRequest.GetLastStatus().ToString());
return;
}
}

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

responseText.Text = strCert;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

// Install response from CA
private void acceptPKCS7Button_Click(object sender, EventArgs e)
{
// Create all the objects that will be required
CX509Enrollment objEnroll = new CX509EnrollmentClass();
string strCert;

try
{
strCert = responseText.Text;

// Install the certificate
objEnroll.Initialize(X509CertificateEnrollmentContext.ContextUser);
objEnroll.InstallResponse(
InstallResponseRestrictionFlags.AllowUntrustedRoot,
strCert,
EncodingType.XCN_CRYPT_STRING_BASE64,
null
);

MessageBox.Show("Certificate installed!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}

 


I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)

  • Hi Alex,

    I have a customer who's using my implementation of your code (you remember, I'm sure). During the process, my program receives an error 0x80004001 when executing the call CspInformations::AddAvailableCsps. Do you have any idea what this means?

    Thanks in advance. If you like you can mail me at robert.collins@datev.de

    Best Regards!

  • I am trying to use your code, but instead of calling the enterprise CA I am making a call to a standalone CA. So basically I am not performing the following

    // Template Extension

                   objExtensionTemplate.InitializeEncode("SmartcardLogon");

                   objPkcs10.X509Extensions.Add((CX509Extension)objExtensionTemplate);

    Everything seems fine and am able to issue the certificate.

    The problem I run into is that if I try to issue another cert, I get an error that the card is being used by another process, when I try to create a privateKey by calling this

    objPrivateKey.Create();

    The only way around it is to manually delete the old certificate adn the associated keys.

    Any idea why that would be happening?

  • duh, i wasnt changing the container name :)

Page 1 of 1 (3 items)
Leave a Comment
  • Please add 4 and 1 and type the answer here:
  • Post
Translate This Page