InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Setting the PIN of a smartcard programmatically

There are certain scenarios where it’s not feasible to require user interaction when accessing the private key of a smartcard. For example, a service does have the ability to provide a user interface. To use a key from a smartcard where a PIN is required, it must be provided to the smartcard using an alternative way. For some operations in .NET, one can use the CspParameters class to provide the PIN. But not all APIs which require smartcard access provide a way to use that class. The SSLStream is such a case. Here is a small extension method which sets the PIN for an X509Certificate2 instance:

static class X509Certificate2Extension
    public static void SetPinForPrivateKey(this X509Certificate2 certificate, string pin)
        if (certificate == null) throw new ArgumentNullException("certificate");
        var key = (RSACryptoServiceProvider)certificate.PrivateKey;

        var providerHandle = IntPtr.Zero;
        var pinBuffer = Encoding.ASCII.GetBytes(pin);

        // provider handle is implicitly released when the certificate handle is released.
        SafeNativeMethods.Execute(() => SafeNativeMethods.CryptAcquireContext(ref providerHandle, 
SafeNativeMethods.CryptContextFlags.Silent)); SafeNativeMethods.Execute(() => SafeNativeMethods.CryptSetProvParam(providerHandle,
pinBuffer, 0)); SafeNativeMethods.Execute(() => SafeNativeMethods.CertSetCertificateContextProperty(
0, providerHandle)); } } internal static class SafeNativeMethods { internal enum CryptContextFlags { None = 0, Silent = 0x40 } internal enum CertificateProperty { None = 0, CryptoProviderHandle = 0x1 } internal enum CryptParameter { None = 0, KeyExchangePin = 0x20 } [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CryptAcquireContext( ref IntPtr hProv, string containerName, string providerName, int providerType, CryptContextFlags flags ); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool CryptSetProvParam( IntPtr hProv, CryptParameter dwParam, [In] byte[] pbData, uint dwFlags); [DllImport("CRYPT32.DLL", SetLastError = true)] internal static extern bool CertSetCertificateContextProperty( IntPtr pCertContext, CertificateProperty propertyId, uint dwFlags, IntPtr pvData ); public static void Execute(Func<bool> action) { if (!action()) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } }

The interesting piece here is, of course, the SetPinForPrivateKey method. It acquires a Win32 cryptographic context, sets the PIN and associates that pin with the certificate. Once you have an X509Certificate2 instance, you can set the PIN with just one line of code:

var certificate = GetCertificate();

The PIN is remembered until the X509Certificate2 instance is open.


This solution is taken from an stackoverflow article. I’ve just made an extension method out of it, converted all those magic numbers to enums and added a little bit of error handling.

Posted by Henning Krause on Monday, November 22, 2010 4:17 PM, last modified on Thursday, November 25, 2010 11:26 PM
Permalink | Post RSSRSS comment feed

Comments (6) -

On 2/2/2012 7:33:09 PM João Miguel wrote:

Jo&#227;o Miguel

First of all let me thank you for this example, it really help me to accomplish what i wanted. However, this only works in Windows 7, not in XP (for me at least!).
I use it in a windows app to sign several PDF documents, without asking several times (one for each document) the pin. In Windows 7, everything works fine, in a Windows XP i get somewhere in the execution  SafeNativeMethods.Execute(() the error:

[System.ComponentModel.Win32Exception] = {&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;An attempt was made to reference a token that does not exist&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;}
StackTrace = &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;   at ...SafeNativeMethods.Execute(Func`1 action) in C:\\...\\X509Certificate2Extension.cs:line 86

Do you have any pointers for me to solve this problem.

Many thanks in advance!

Best Regards

Jo&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;#227;o Miguel

On 2/25/2012 9:48:11 PM Karumba wrote:


Thank you for the article and the refence.

On 12/7/2012 4:26:21 AM Florian D. wrote:

Florian D.

You saved my night... ehm day!

On 1/17/2013 3:26:23 PM prostynick wrote:


Bless you!

On 9/13/2013 9:59:35 AM Lütfullah Kuş wrote:

L&#252;tfullah Kuş

U realy saved my day Smile thx a lot..

On 11/7/2013 4:31:29 PM Rohan wrote:


Can you please help me to find exact method for How to change user PIN? or Security Officer (SO) PIN? of smart card?

Thanks in advance.