A3 Digital Certificate with C # X509Certificate2

1
When I'm issuing MDF-e / NF-e / CT-e (any tax document) using the A3 certificate, I'd better set the pin via code using the method here

/// <summary>
/// Classe para passar o Pin Code por baixo do código 
/// (a caixa de dialógo pedindo o Pin Code não aparecerá para o usuário).
/// <athor>Renan Borges</athor>
/// <date>02/05/2014</date>
/// </summary>
public static class clsX509Certificate2Extension
{
    /// <summary>
    /// Passa PIN Code (Senha/Password) para Certificados
    ///  eToken como o A3 do SERASA do Brasil
    /// </summary>
    /// <param name="_Certificado">O Certificado que está sendo usado 
    /// para a criptografia</param>
    /// <param name="_PinPassword">O Pin Code / Senha / Password</param>
    public static void SetPinPrivateKey(this X509Certificate2 _Certificado, string _PinPassword)
    {
        if(_Certificado == null) throw new ArgumentNullException("_Certificado == null!");
        var key = (RSACryptoServiceProvider)_Certificado.PrivateKey;

        IntPtr ProviderHandle = IntPtr.Zero;
        byte[] PinBuffer = Encoding.ASCII.GetBytes(_PinPassword);

        //Não é necessário descarregar o handle
        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(
                                       _Certificado.Handle,
                                       SafeNativeMethods.CertificateProperty.CryptoProviderHandle,
                                       0,
                                       ProviderHandle)
                                  );
    }

    /// <summary>
    /// Retorna true se o certificado for do tipo A3.
    /// </summary>
    /// <param name="x509cert">Certificado que deverá ser validado se é A3 ou não.</param>
    /// <returns></returns>
    public static bool IsA3(this X509Certificate2 x509cert)
    {
        if (x509cert == null) 
           return false;

        bool result = false;

        try
        {
            RSACryptoServiceProvider service = x509cert.PrivateKey as RSACryptoServiceProvider;

            if(service != null)
            {
                if(service.CspKeyContainerInfo.Removable &&
                service.CspKeyContainerInfo.HardwareDevice)
                    result = true;
            }
        }
        catch
        {
            //assume que é false
            result = false;
        }

        return result;
    }
}
/// <summary>
/// Funções da API do Windows que realmente executam a passagem do PIN
/// </summary>
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());
        }
    }
}

obs: the method class ai and the unimake framework uninfe

In my tests when I send only a single document type, for example I am issuing mdf-and non-stop .. canceling, terminating, authorizing, query protocol anyway .. I will be using the issuance of an electronic tax document ..

Moving on to another CT-document and I'm issuing normally too .. (it never asks for the password, the password has been set by those methods there)

So I keep changing in mdf-e and ct-e when suddenly, it releases me a cloud not create ssl / tls

"could not create ssl / tls secure channel"

Remembering that it works normally for about 10 ~ 20 minutes it always varies in the number of minutes until it starts releasing this exeption

The exption only disappears when I close and open the application again

This left me confused because the only link to the system I have are local variables that instantiated within digital certificate methods, but somehow he created a link with the application itself. I am assuming that the certificate itself creates this link (actually I still do not know the reason and just assuming ...).

Windows 10 build 1486 .Net 4.5

    
asked by anonymous 26.01.2017 / 18:25

1 answer

1

Solved .. to solve I needed to cache the certificate ie .. with the same instance I used to sign and send to the thread. It was not like this before.

    
29.01.2017 / 03:43