简体   繁体   English

如何提供PIN以编程方式访问智能卡?

[英]How to provide PIN to access smartcard programmatically?

I'm using certificates to secure my communications between client and server (no code, just endpoint configuration). 我正在使用证书来保护客户端和服务器之间的通信安全(没有代码,只有端点配置)。 Certificates are currently stored in ACOS5 smart cards. 证书当前存储在ACOS5智能卡中。 Everything works very well except that every time when WCF creates a new channel to access the server, the ACOS5 driver asks user to enter “User PIN”. 一切工作都很好,除了每次WCF创建访问服务器的新通道时,ACOS5驱动程序都会要求用户输入“用户PIN”。 Unfortunately, it happens quite often. 不幸的是,它经常发生。

Is there any way to configure driver to cache PIN that user has already entered within current process at least for some time or how can I cache pin and provide it every time programmatically within same session? 有什么方法可以配置驱动程序以缓存用户已经在当前进程中输入的PIN至少一段时间,或者如何在同一会话中每次以编程方式缓存PIN并提供它?

I have found some useful in this article : 我在这篇文章中发现了一些有用的东西:

This is because in previous versions of Windows each CSP would cache the PIN you entered, but Windows 7 actually converts the PIN to a secure token and caches that. 这是因为在Windows的早期版本中,每个CSP都会缓存您输入的PIN,但是Windows 7实际上会将PIN转换为安全令牌并对其进行缓存。 Unfortunately there's only one global token cache but the CSPs can't use tokens generated by others, so first the smart card CSP prompts you and caches a token, then SSL prompts you and caches its own token (overwriting the first one), then the smart card system prompts you again (because its cached token is gone). 不幸的是,只有一个全局令牌缓存,但是CSP无法使用其他令牌生成的令牌,因此,智能卡CSP首先会提示您并缓存令牌,然后SSL会提示您并缓存自己的令牌(覆盖第一个令牌),然后智能卡系统会再次提示您(因为其缓存的令牌已消失)。

But I can't use solution that was proposed by author. 但是我不能使用作者提出的解决方案。 So what should I do? 所以我该怎么做?

Actually I have found answer on my question: the described behavior caused by bug in Advanced Card Systems CSP v1.9. 实际上,我在以下问题上找到了答案:所描述的行为是由Advanced Card Systems CSP v1.9中的错误引起的。 After switching to Alladin eToken application works as it should. 切换到Alladin后,eToken应用程序将正常运行。 So I can't provide PIN from code but it is remembered by CSP after entering and providing from code is not required. 因此,我无法从代码中提供PIN,但CSP会记住该PIN,并且不需要从代码中提供。 More good news: user sees PIN request in familiar dialog from CSP in this case. 更多好消息:在这种情况下,用户会在CSP熟悉的对话框中看到PIN请求。

This is a way we found and use from many years in our main application: 这是我们多年来在主要应用程序中发现和使用的一种方法:

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 full post and author is here: http://www.infinitec.de/post/2010/11/22/Setting-the-PIN-of-a-smartcard-programmatically.aspx 完整的帖子和作者在这里: http : //www.infinitec.de/post/2010/11/22/Setting-the-PIN-of-a-smartcard-programmatically.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM