tramites software quien puede obtener nie gratis fnmt electronico descargar certificado c# cryptography visual-studio-2013 smartcard

c# - quien - software certificado digital



encontrar certificado en tarjeta inteligente actualmente en el lector (2)

Me preguntaba por qué haces foreach a través de todos los certificados en una tienda cuando conoces el tema del certificado. Mi sugerencia sería:

public static byte[] Sign(Stream inData, string certSubject) { // Access Personal (MY) certificate store of current user X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser); my.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); var foundCerts = my.Certificates.Find(X509FindType.FindBySubjectName, certSubject, true); if (foundCerts.Count == 0) throw new Exception("No valid cert was found"); var cert = foundCerts[0]; RSACryptoServiceProvider csp = null; // let us assume that certSubject is unique if (cert.HasPrivateKey) { csp = (RSACryptoServiceProvider)cert.PrivateKey; if (csp.CspKeyContainerInfo.HardwareDevice) Console.WriteLine("hardware"); Console.WriteLine(cert.ToString()); } else { throw new Exception("No private key assigned to this certificate"); } // Hash the data SHA1Managed sha1 = new SHA1Managed(); byte[] hash = sha1.ComputeHash(inData); // Sign the hash return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA1")); }

Si no conoce el tema exacto o espera encontrar otro certificado con este tema, probablemente no le sirva.

Estoy usando Visual Studio 2013 (C #) para firmar digitalmente el documento usando el certificado de la tarjeta inteligente. No puedo identificar el certificado actualmente insertado en el lector de tarjetas :(

Windows copia los certificados de todas las tarjetas insertadas en el lector y lo mantiene en la tienda. Quiero usar solo la tarjeta en el lector.

el código que uso es

public static byte[] Sign(Stream inData, string certSubject) { // Access Personal (MY) certificate store of current user X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser); my.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); // Find the certificate we''ll use to sign RSACryptoServiceProvider csp = null; foreach (X509Certificate2 cert in my.Certificates) { if (cert.Subject.Contains(certSubject)) { // We found it. // Get its associated CSP and private key if (cert.HasPrivateKey) { csp = (RSACryptoServiceProvider)cert.PrivateKey; if (csp.CspKeyContainerInfo.HardwareDevice) Console.WriteLine("hardware"); Console.WriteLine(cert.ToString()); } } } if (csp == null) { throw new Exception("No valid cert was found"); } // Hash the data SHA1Managed sha1 = new SHA1Managed(); byte[] hash = sha1.ComputeHash(inData); // Sign the hash return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA1")); }

Pero cuando se accede al usuario cert.PrivateKey, se le solicita que inserte la tarjeta en el lector. Cómo detectar y omitir este mensaje para la tarjeta o detectar ese certificado ¿TIENE la tarjeta correspondiente actualmente en el lector?

Solo quiero usar el certificado de la tarjeta inteligente actualmente en el lector.


Me temo que no es posible detectar si la tarjeta que contiene el objeto específico X509Certificate2 está presente en el lector mediante el uso de API .NET estándar. Lo mejor (muy hackish) que pude llegar es esto:

public static X509Certificate2 GetDefaultCertificateStoredOnTheCard() { // Acquire public key stored in the default container of the currently inserted card CspParameters cspParameters = new CspParameters(1, "Microsoft Base Smart Card Crypto Provider"); RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParameters); string pubKeyXml = rsaProvider.ToXmlString(false); // Find the certficate in the CurrentUser/My store that matches the public key X509Store x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser); x509Store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); foreach (X509Certificate2 cert in x509Store.Certificates) { if ((cert.PublicKey.Key.ToXmlString(false) == pubKeyXml) && cert.HasPrivateKey) return cert; } return null; }

Sin embargo, este método es confiable solo cuando se cumplen las siguientes condiciones:

  1. Su tarjeta es accesible a través de Minidriver y Microsoft Base Smart Card Crypto Provider.
  2. Solo hay un lector conectado a su computadora con la tarjeta inteligente presente.
  3. Solo hay un certificado presente en la tarjeta actualmente insertada en el lector.

Cuando hay múltiples lectores con tarjetas inteligentes conectadas o múltiples certificados presentes en la tarjeta, no puede estar seguro de cuál será devuelto por este método.

Tenga en cuenta que también hay otras API disponibles que pueden acceder a la tarjeta inteligente. Un ejemplo de tal API es PKCS # 11. Puede ser una exageración para operaciones simples, pero puede otorgarle un control total sobre su tarjeta y los objetos almacenados en ella. Si está interesado y su tarjeta inteligente viene con la biblioteca PKCS # 11, puede echar un vistazo a mi proyecto Pkcs11Interop, que aporta toda la potencia de la API PKCS # 11 al entorno .NET.

Espero que esto ayude :)

Editado para eliminar la restricción de "certificado único":

He modificado ligeramente el código. Ahora usa Crypto API no administrada para enumerar los nombres de todos los contenedores administrados por Microsoft Base Smart Crypto Provider y luego busca los objetos X509Certificate2 correspondientes en el CurrentUser / My store. Tenga en cuenta que este enfoque también es muy hackish y es posible que el código provisto no funcione de manera confiable con todas las tarjetas / minidrivers disponibles en el mercado. Por lo general, es mejor y más fácil dejar que el usuario elija el certificado correcto del diálogo de selección de certificados incorporado.

using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; namespace CSP { public static class BaseSmartCardCryptoProvider { private const string _providerName = "Microsoft Base Smart Card Crypto Provider"; private static class NativeMethods { public const uint PROV_RSA_FULL = 0x00000001; public const uint CRYPT_VERIFYCONTEXT = 0xF0000000; public const uint CRYPT_FIRST = 0x00000001; public const uint CRYPT_NEXT = 0x00000002; public const uint ERROR_NO_MORE_ITEMS = 0x00000103; public const uint PP_ENUMCONTAINERS = 0x00000002; [DllImport("advapi32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] public static extern bool CryptAcquireContext( ref IntPtr phProv, [MarshalAs(UnmanagedType.LPStr)] string pszContainer, [MarshalAs(UnmanagedType.LPStr)] string pszProvider, uint dwProvType, uint dwFlags); [DllImport("advapi32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)] public static extern bool CryptGetProvParam( IntPtr hProv, uint dwParam, [MarshalAs(UnmanagedType.LPStr)] StringBuilder pbData, ref uint pdwDataLen, uint dwFlags); [DllImport("advapi32.dll", SetLastError = true)] public static extern bool CryptReleaseContext( IntPtr hProv, uint dwFlags); } public static List<X509Certificate2> GetCertificates() { List<X509Certificate2> certs = new List<X509Certificate2>(); X509Store x509Store = null; try { x509Store = new X509Store(StoreName.My, StoreLocation.CurrentUser); x509Store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); List<string> containers = GetKeyContainers(); foreach (string container in containers) { CspParameters cspParameters = new CspParameters((int)NativeMethods.PROV_RSA_FULL, _providerName, container); cspParameters.Flags = CspProviderFlags.UseExistingKey; string pubKeyXml = null; using (RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParameters)) pubKeyXml = rsaProvider.ToXmlString(false); foreach (X509Certificate2 cert in x509Store.Certificates) { if ((cert.PublicKey.Key.ToXmlString(false) == pubKeyXml) && cert.HasPrivateKey) certs.Add(cert); } } } finally { if (x509Store != null) { x509Store.Close(); x509Store = null; } } return certs; } private static List<string> GetKeyContainers() { List<string> containers = new List<string>(); IntPtr hProv = IntPtr.Zero; try { if (!NativeMethods.CryptAcquireContext(ref hProv, null, _providerName, NativeMethods.PROV_RSA_FULL, NativeMethods.CRYPT_VERIFYCONTEXT)) throw new Win32Exception(Marshal.GetLastWin32Error()); uint pcbData = 0; uint dwFlags = NativeMethods.CRYPT_FIRST; if (!NativeMethods.CryptGetProvParam(hProv, NativeMethods.PP_ENUMCONTAINERS, null, ref pcbData, dwFlags)) throw new Win32Exception(Marshal.GetLastWin32Error()); StringBuilder sb = new StringBuilder((int)pcbData + 1); while (NativeMethods.CryptGetProvParam(hProv, NativeMethods.PP_ENUMCONTAINERS, sb, ref pcbData, dwFlags)) { containers.Add(sb.ToString()); dwFlags = NativeMethods.CRYPT_NEXT; } int err = Marshal.GetLastWin32Error(); if (err != NativeMethods.ERROR_NO_MORE_ITEMS) throw new Win32Exception(err); if (hProv != IntPtr.Zero) { if (!NativeMethods.CryptReleaseContext(hProv, 0)) throw new Win32Exception(Marshal.GetLastWin32Error()); hProv = IntPtr.Zero; } } catch { if (hProv != IntPtr.Zero) { if (!NativeMethods.CryptReleaseContext(hProv, 0)) throw new Win32Exception(Marshal.GetLastWin32Error()); hProv = IntPtr.Zero; } throw; } return containers; } } }

Simplemente llame al método GetCertificates () de la clase proporcionada para verificar si este código funciona con su tarjeta:

List<X509Certificate2> certs = CSP.BaseSmartCardCryptoProvider.GetCertificates();