我正在使用证书来保护我在客户端和服务器之间的通信(没有代码,只有端点配置)。证书目前存储在ACOS5智能卡中。除了每次WCF创建新频道以访问服务器时,一切都运行良好,ACOS5驱动程序要求用户输入“用户PIN”。不幸的是,它经常发生。
有没有办法配置驱动程序来缓存用户已经在当前进程中输入的PIN至少一段时间,或者我如何在同一会话中以编程方式缓存引脚并提供它?
我在这个article中找到了一些有用的东西:
这是因为在之前的版本中 Windows每个CSP都会缓存 您输入的PIN,但Windows 7 实际上将PIN转换为安全 令牌和缓存。不幸 只有一个全局令牌缓存 但是CSP不能使用令牌 由他人产生,所以首先 智能卡CSP会提示您和缓存 一个令牌,然后SSL会提示您和 缓存自己的令牌(覆盖 第一个),然后是智能卡系统 再次提示你(因为它的缓存 令牌消失了。)
但我不能使用作者提出的解决方案。那我该怎么办?
答案 0 :(得分:1)
实际上我已经在我的问题上找到了答案:由Advanced Card Systems CSP v1.9中的错误引起的描述行为。切换到Alladin后,eToken应用程序可以正常工作。 因此,我无法从代码中提供PIN,但在输入代码后不会被CSP记住,并且不需要代码提供。更多好消息:在这种情况下,用户可以在熟悉的CSP对话框中看到PIN请求。
答案 1 :(得分:0)
这是我们多年来在主要应用程序中发现和使用的一种方法:
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