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 :)