How to import an X509Certificate in a PKCS#11 token/HSM using C#

The simplest way to import an X509Certificate in a PKCS#11 token, smart card or HSM is by using NCryptoki.
NCryptoki is a library for .NET framework that implements the PKCS#11 specifications and supplies an API for C#, VB.NET, Visual Basic 6, Delphi and other COM interop languages for integrating a PKCS#11 compliant token in any application.
NCryptoki allows to avoid from the extremely tedious work needed to import in your favorite programming language the PKCS#11 functions exposed by native, unmanaged PKCS#11 implementations reducing the complexity of the code and saving a lot of development time.
NCryptoki maps the cryptoki's functions defined in PKCS#11 specification in a set of high level classes usable in C#, VB.NET and propose a programming paradigm that allows to integrate your PKCS#11 compliant token in your applications easily with a few lines of code.
NCryptoki supplies also a COM interface that allows to use the supplied classes in any language that supports COM interop like Visual Basic 6, Delphi etc.
For more information about NCryptoki and for the full documentation visit: http://www.ncryptoki.com.
The programming paradigm is very similar to the one described in the PKCS#11 specifications by using the C programming language:  the PKCS#11 C functions are mapped into a set of .NET classes that follows the same classification described in that specifications.
As an example, let's see in the following snippet how to import an X509Certificate in a token:

// Creates a Cryptoki object and attach it to the
// PKCS#11 native library smaoscki.dll
Cryptoki cryptoki = new Cryptoki("smaoscki.dll");
int nRet = cryptoki.Initialize();
if (nRet != 0)
    throw new Exception("Initialize error: " + nRet);

// Reads the set of available slots
SlotList slots = cryptoki.Slots;
if (slots.Count == 0)
    throw new Exception("No slots available");

// Gets the first slot available
Slot slot = slots[0];

// check whether a token is in the slot
if(!slot.IsTokenInserted)
    throw new Exception("No token available in the slot");

Token token = slot.Token;

// Opens a read/write serial session
Session session = token.OpenSession (Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);

// Executes the login passing the user PIN
nRet = session.Login((int)Session.CKU_USER, "12345678");
if (nRet != 0)
    throw new Exception("Login Error: " + nRet);
// read the certificate from a base64 string
// read from a file
X509Certificate2 cert = new X509Certificate2(Convert.FromBase64String(certPEM));

// gets the id in binary format
byte[] id = Encoding.ASCII.GetBytes("MyKeyPairID");

// creates the template
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CERTIFICATE_TYPE, Certificate.CKC_X_509));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, false))
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "MyLabel"));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, id));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_SUBJECT, cert.SubjectName.RawData));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_ISSUER, cert.Issuer));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_SERIAL_NUMBER, cert.SerialNumber));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_VALUE, cert.RawData));

// creates the certificate object in the token
CryptokiObject certificate = session.Objects.Create(template);

Add comment