En ocasiones, especialmente si no utiliza el nombre del contenedor de claves predeterminado en la tarjeta inteligente (recomendado por Microsoft), los certificados no se copian en el almacén de certificados local. La solución es usar crypto api para acceder a la clave con KP_CERTIFICATE, construir el certificado a partir de los datos recuperados y asignarle un nuevo RSACryptoServiceProvider construido utilizando su propio nombre de contenedor de claves.
El seudo código C# siguiente:
int reti = CryptoApi.CryptGetUserKey(_hprovider, keytype, ref userKey);
if (reti)
{
reti =CryptoApi.CryptGetKeyParam(_userKey, KP_CERTIFICATE, ref pbdata, ref pwddatalen, 0);
}
if (reti || pwddatalen>0)
{
byte[] data = new byte[pwddatalen];
ret = CryptoApi.CryptGetKeyParam(_userKey, KP_CERTIFICATE, data, ref pwddatalen, 0);
if (ret)
{
X509Certificate2 c = new X509Certificate2(data);
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection col = store.Certificates.Find(X509FindType.FindByThumbprint, c.Thumbprint, validonly);
store.Close();
if (col.Count != 1)
{
//not found in store - CSP didn't copy it
c.PrivateKey = PrivateKey(keytype);
return c;
}
else
{
return col[0];
}
}
}
private RSACryptoServiceProvider PrivateKey (KeyType keytype)
{
CspParameters csparms = new CspParameters();
csparms.KeyContainerName = _containerName;
csparms.ProviderName = _provider;
csparms.ProviderType = 1;
csparms.Flags = CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey;
csparms.KeyNumber = (int)keytype;
return new RSACryptoServiceProvider(csparms);
}
¿Estoy un poco confundido sobre cuándo se necesitaría ese código? Si conoce la línea de asunto de la tarjeta inteligente, almacénela para cada uno de sus usuarios al registrarse y luego almacene el certificado en la base de datos; luego, cada vez que alguien intente iniciar sesión, compare el certificado en la base de datos con el certificado que figura en Solicitud .ClientCertificate, ¿verdad? – Dexter
Solo puede almacenar parte pública del certificado en alguna parte, y la comparación de partes públicas del certificado no es suficiente para probar la posesión de la clave privada. Por lo tanto, necesita acceso a una clave privada para firmar algunos datos y probarlo. El proveedor de cifrado a veces pondrá la clave privada disponible para el almacén de certificados de forma automática y, a veces, no. En caso de que no lo haga, esta es la forma de obtenerlo. –
¿Hay algún artículo en el que encuentre este tipo de código? Tu código está un poco incompleto con las variables no declaradas. ¿Dónde hay un artículo de C# que describe este proceso de verificación de la validez de claves privadas? Siempre asumí una verificación simple de la certificación válida usando X509Certificate para verificar si el hash es un hash válido en el Certificado del cliente podría ser suficiente, pero sí, supongo que se puede falsificar con un certificado autofirmado. Cualquier información sería de gran ayuda. – Dexter