簡體   English   中英

如何提供PIN以編程方式訪問智能卡?

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

我正在使用證書來保護客戶端和服務器之間的通信安全(沒有代碼,只有端點配置)。 證書當前存儲在ACOS5智能卡中。 一切工作都很好,除了每次WCF創建訪問服務器的新通道時,ACOS5驅動程序都會要求用戶輸入“用戶PIN”。 不幸的是,它經常發生。

有什么方法可以配置驅動程序以緩存用戶已經在當前進程中輸入的PIN至少一段時間,或者如何在同一會話中每次以編程方式緩存PIN並提供它?

我在這篇文章中發現了一些有用的東西:

這是因為在Windows的早期版本中,每個CSP都會緩存您輸入的PIN,但是Windows 7實際上會將PIN轉換為安全令牌並對其進行緩存。 不幸的是,只有一個全局令牌緩存,但是CSP無法使用其他令牌生成的令牌,因此,智能卡CSP首先會提示您並緩存令牌,然后SSL會提示您並緩存自己的令牌(覆蓋第一個令牌),然后智能卡系統會再次提示您(因為其緩存的令牌已消失)。

但是我不能使用作者提出的解決方案。 所以我該怎么做?

實際上,我在以下問題上找到了答案:所描述的行為是由Advanced Card Systems CSP v1.9中的錯誤引起的。 切換到Alladin后,eToken應用程序將正常運行。 因此,我無法從代碼中提供PIN,但CSP會記住該PIN,並且不需要從代碼中提供。 更多好消息:在這種情況下,用戶會在CSP熟悉的對話框中看到PIN請求。

這是我們多年來在主要應用程序中發現和使用的一種方法:

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());
        }
    }
}

完整的帖子和作者在這里: 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