Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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)
Comments
- Anonymous
November 12, 2010
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.deBest Regards! - Anonymous
April 22, 2011
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 thisobjPrivateKey.Create();The only way around it is to manually delete the old certificate adn the associated keys.Any idea why that would be happening? - Anonymous
April 22, 2011
duh, i wasnt changing the container name :)