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

Wcf 如何提供PIN以编程方式访问智能卡?,wcf,wcf-security,smartcard,Wcf,Wcf Security,Smartcard,我使用证书来保护客户端和服务器之间的通信(没有代码,只有端点配置)。证书当前存储在ACOS5智能卡中。除了每次WCF创建一个新通道访问服务器时,ACOS5驱动程序都会要求用户输入“用户PIN”之外,一切都很正常。不幸的是,这种情况经常发生 是否有任何方法可以将驱动程序配置为缓存用户在当前进程中至少已输入一段时间的PIN,或者如何缓存PIN并在同一会话中以编程方式每次提供PIN 我在这方面发现了一些有用的东西: 这是因为在以前的版本中 每个CSP将缓存 您输入的PIN码,但Windows 7 实际

我使用证书来保护客户端和服务器之间的通信(没有代码,只有端点配置)。证书当前存储在ACOS5智能卡中。除了每次WCF创建一个新通道访问服务器时,ACOS5驱动程序都会要求用户输入“用户PIN”之外,一切都很正常。不幸的是,这种情况经常发生

是否有任何方法可以将驱动程序配置为缓存用户在当前进程中至少已输入一段时间的PIN,或者如何缓存PIN并在同一会话中以编程方式每次提供PIN

我在这方面发现了一些有用的东西:

这是因为在以前的版本中 每个CSP将缓存 您输入的PIN码,但Windows 7 实际上将PIN码转换为安全密码 令牌并将其缓存。不幸的是 只有一个全局令牌缓存 但是CSP不能使用代币 由他人产生,所以首先 智能卡CSP提示您和缓存 一个令牌,然后SSL提示您和 缓存自己的令牌(覆盖 首先是一个),然后是智能卡系统 再次提示您(因为它已缓存) 代币不见了)


但我不能使用作者提出的解决方案。那么我该怎么办呢?

事实上,我已经找到了问题的答案:所描述的行为是由高级卡系统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());
        }
    }
}
静态类X509Certificate2Extension
{
public static void SetPinForPrivateKey(此X509Certificate2证书,字符串pin)
{
如果(证书==null)抛出新的ArgumentNullException(“证书”);
var key=(rsacyptoserviceprovider)certificate.PrivateKey;
var providerHandle=IntPtr.Zero;
var pinBuffer=Encoding.ASCII.GetBytes(pin);
//当证书句柄被释放时,提供程序句柄被隐式释放。
SafeNativeMethods.Execute(()=>SafeNativeMethods.CryptAcquireContext(参考providerHandle,
key.CspKeyContainerInfo.KeyContainerName,
key.CspKeyContainerInfo.ProviderName,
key.CspKeyContainerInfo.ProviderType,
SafeNativeMethods.CryptContextFlags.Silent);
SafeNativeMethods.Execute(()=>SafeNativeMethods.CryptoSetProvParam(providerHandle,
SafeNativeMethods.CryptParameter.KeyExchangePin,
pinBuffer,0);
SafeNativeMethods.Execute(()=>SafeNativeMethods.CertSetCertificateContextProperty(
证书,句柄,
安全方法.CertificateProperty.CryptoProviderHandle,
0,providerHandle));
}
}
内部静态类SafeNativeMethods
{
内部枚举CryptContextFlags
{
无=0,
无声=0x40
}
内部枚举证书属性
{
无=0,
CryptoProviderHandle=0x1
}
内部枚举密码参数
{
无=0,
KeyExchangePin=0x20
}
[DllImport(“advapi32.dll”,CharSet=CharSet.Auto,SetLastError=true)]
公共静态外部布尔加密上下文(
参考IntPtr hProv,
字符串容器名称,
字符串提供程序名称,
int providerType,
CryptContextFlags标志
);
[DllImport(“advapi32.dll”,SetLastError=true,CharSet=CharSet.Auto)]
公共静态外部布尔CryptSetProvParam(
IntPtr hProv,
密码参数dwParam,
[In]字节[]pbData,
uint(dwFlags);
[DllImport(“CRYPT32.DLL”,SetLastError=true)]
内部静态外部布尔CertSetCertificateContextProperty(
IntPtr pCertContext,
证书财产ID,
uint-dwFlags,
IntPtr pvData
);
公共静态无效执行(Func操作)
{
如果(!action())
{
抛出新的Win32Exception(Marshal.GetLastWin32Error());
}
}
}
全文及作者如下: