InfiniTec - Henning Krauses Blog

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

Enabling Secure PIN Entry on NetKey 3.0 Cards

Posted under Smartcards | Comments (0)

If you use the smartcard Cryptographic Provider provided by T-Systems for the card, you’ll notice that by default you are prompted to enter the PIN of the smartcard via the standard keyboard, even if you have class 2 reader, which has its own pin pad. This behavior can be easily changed with a small change in the registry. Just open the Windows Registry Editor and navigate to the node HKEY_LOCAL_MACHINE\SOFTWARE\T-Systems\CardMiniDriverTCOS3\MSCP and change the value of the field usePinPad from false to true. The next time you are required to enter the PIN, you are asked to do it via the pin pad of the smartcard reader. You might need to remove and insert the smartcard to get this to work.


Posted by Henning Krause on Friday, November 26, 2010 9:01 AM, last modified on Friday, November 26, 2010 9:01 AM
Permalink | Post RSSRSS comment feed

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, 
key.CspKeyContainerInfo.KeyContainerName,
key.CspKeyContainerInfo.ProviderName,
key.CspKeyContainerInfo.ProviderType,
SafeNativeMethods.CryptContextFlags.Silent)); SafeNativeMethods.Execute(() => SafeNativeMethods.CryptSetProvParam(providerHandle,
SafeNativeMethods.CryptParameter.KeyExchangePin,
pinBuffer, 0)); SafeNativeMethods.Execute(() => SafeNativeMethods.CertSetCertificateContextProperty(
certificate.Handle,
SafeNativeMethods.CertificateProperty.CryptoProviderHandle,
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();
certificate.SetPinForPrivateKey("123456");

The PIN is remembered until the X509Certificate2 instance is open.

Credits

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