From 3fb1aa23303e1f612caa200449141bb9ea81a42f Mon Sep 17 00:00:00 2001 From: Danilo Breda Date: Tue, 16 Jan 2024 14:50:42 -0300 Subject: [PATCH] =?UTF-8?q?feito=20nova=20configuracao=20para=20passar=20o?= =?UTF-8?q?=20X509KeyStorageFlags=20ao=20gerar=20instancia=20de=20X509Cert?= =?UTF-8?q?ificate2=20usando=20byte=20como=20certificado=20em=20mem=C3=B3r?= =?UTF-8?q?ia,=20o=20mesmo=20funciona=20para=20certificados=20em=20arquivo?= =?UTF-8?q?s.=20O=20problema=20resolve=20se=20voc=C3=AA=20estiver=20enfren?= =?UTF-8?q?tando=20problemas=20relacionados=20a=20permiss=C3=B5es=20de=20a?= =?UTF-8?q?cesso=20ao=20carregar=20certificados,=20pode=20ser=20=C3=BAtil?= =?UTF-8?q?=20usar=20X509KeyStorageFlags.EphemeralKeySet=20que=20=C3=A9=20?= =?UTF-8?q?poss=C3=ADvel=20em=20.net=206=20+?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DFe.Testes/DFe.Testes.csproj | 11 ++- DFe.Utils/Assinatura/CertificadoDigital.cs | 89 ++++++++++++------- DFe.Utils/CertificadoDigitalUtils.cs | 8 +- DFe.Utils/ConfiguracaoCertificado.cs | 16 ++++ .../NFe.Danfe.App.Teste.Html.csproj | 2 +- .../NFe.Danfe.Fast.Skia.csproj | 2 +- NFe.Danfe.Html/NFe.Danfe.Html.csproj | 2 +- NFe.Utils.Testes/NFe.Utils.Testes.csproj | 6 +- 8 files changed, 88 insertions(+), 48 deletions(-) diff --git a/DFe.Testes/DFe.Testes.csproj b/DFe.Testes/DFe.Testes.csproj index edee1fefa..c4d819d8c 100644 --- a/DFe.Testes/DFe.Testes.csproj +++ b/DFe.Testes/DFe.Testes.csproj @@ -7,10 +7,13 @@ - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/DFe.Utils/Assinatura/CertificadoDigital.cs b/DFe.Utils/Assinatura/CertificadoDigital.cs index 682964396..987bfbec0 100644 --- a/DFe.Utils/Assinatura/CertificadoDigital.cs +++ b/DFe.Utils/Assinatura/CertificadoDigital.cs @@ -67,14 +67,14 @@ public static X509Store ObterX509Store(OpenFlags openFlags) /// Arquivo do certificado digital /// Senha do certificado digital /// - private static X509Certificate2 ObterDeArquivo(string arquivo, string senha) + private static X509Certificate2 ObterDeArquivo(string arquivo, string senha, X509KeyStorageFlags keyStorageFlag) { if (!File.Exists(arquivo)) { throw new Exception(string.Format("Certificado digital {0} não encontrado!", arquivo)); } - var certificado = new X509Certificate2(arquivo, senha, X509KeyStorageFlags.MachineKeySet); + var certificado = new X509Certificate2(arquivo, senha, keyStorageFlag); return certificado; } @@ -85,11 +85,11 @@ private static X509Certificate2 ObterDeArquivo(string arquivo, string senha) /// Array de bytes do certificado digital /// Senha do certificado digital /// - private static X509Certificate2 ObterDoArrayBytes(byte[] arrayBytes, string senha) + private static X509Certificate2 ObterDoArrayBytes(byte[] arrayBytes, string senha, X509KeyStorageFlags keyStorageFlag) { try { - var certificado = new X509Certificate2(arrayBytes, senha, X509KeyStorageFlags.MachineKeySet); + var certificado = new X509Certificate2(arrayBytes, senha, keyStorageFlag); return certificado; } catch (Exception ex) @@ -148,24 +148,34 @@ private static X509Certificate2 ObterDoRepositorioPassandoPin(string serial, str /// private static void DefinirPinParaChavePrivada(this X509Certificate2 certificado, string pin) { - if (certificado == null) throw new ArgumentNullException("certificado"); - var key = (RSACryptoServiceProvider)certificado.PrivateKey; - - var providerHandle = IntPtr.Zero; - var pinBuffer = Encoding.ASCII.GetBytes(pin); - - MetodosNativos.Executar(() => MetodosNativos.CryptAcquireContext(ref providerHandle, - key.CspKeyContainerInfo.KeyContainerName, - key.CspKeyContainerInfo.ProviderName, - key.CspKeyContainerInfo.ProviderType, - MetodosNativos.CryptContextFlags.Silent)); - MetodosNativos.Executar(() => MetodosNativos.CryptSetProvParam(providerHandle, - MetodosNativos.CryptParameter.KeyExchangePin, - pinBuffer, 0)); - MetodosNativos.Executar(() => MetodosNativos.CertSetCertificateContextProperty( - certificado.Handle, - MetodosNativos.CertificateProperty.CryptoProviderHandle, - 0, providerHandle)); + /// Suprimindo o aviso CA1416 para esta região de código específica +#pragma warning disable CA1416 + if (Environment.OSVersion.Platform == PlatformID.Win32NT || Environment.OSVersion.Platform == PlatformID.Win32Windows || Environment.OSVersion.Platform == PlatformID.Win32S) + { + if (certificado == null) throw new ArgumentNullException("certificado"); + var key = (RSACryptoServiceProvider)certificado.PrivateKey; + + var providerHandle = IntPtr.Zero; + var pinBuffer = Encoding.ASCII.GetBytes(pin); + + MetodosNativos.Executar(() => MetodosNativos.CryptAcquireContext(ref providerHandle, + key.CspKeyContainerInfo.KeyContainerName, + key.CspKeyContainerInfo.ProviderName, + key.CspKeyContainerInfo.ProviderType, + MetodosNativos.CryptContextFlags.Silent)); + MetodosNativos.Executar(() => MetodosNativos.CryptSetProvParam(providerHandle, + MetodosNativos.CryptParameter.KeyExchangePin, + pinBuffer, 0)); + MetodosNativos.Executar(() => MetodosNativos.CertSetCertificateContextProperty( + certificado.Handle, + MetodosNativos.CertificateProperty.CryptoProviderHandle, + 0, providerHandle)); + } + else + { + throw new NotSupportedException("Metodo DefinirPinParaChavePrivada com suporte apenas no Windows atualmente!"); + } +#pragma warning restore CA1416 } /// @@ -179,9 +189,9 @@ private static X509Certificate2 ObterDadosCertificado(ConfiguracaoCertificado co case TipoCertificado.A1Repositorio: return ObterDoRepositorio(configuracaoCertificado.Serial, OpenFlags.MaxAllowed); case TipoCertificado.A1ByteArray: - return ObterDoArrayBytes(configuracaoCertificado.ArrayBytesArquivo, configuracaoCertificado.Senha); + return ObterDoArrayBytes(configuracaoCertificado.ArrayBytesArquivo, configuracaoCertificado.Senha, configuracaoCertificado.KeyStorageFlags); case TipoCertificado.A1Arquivo: - return ObterDeArquivo(configuracaoCertificado.Arquivo, configuracaoCertificado.Senha); + return ObterDeArquivo(configuracaoCertificado.Arquivo, configuracaoCertificado.Senha, configuracaoCertificado.KeyStorageFlags); case TipoCertificado.A3: return ObterDoRepositorioPassandoPin(configuracaoCertificado.Serial, configuracaoCertificado.Senha); default: @@ -294,7 +304,7 @@ public static void VerificaValidade(this X509Certificate2 x509Certificate2) throw new ArgumentException("Certificado digital vencido na data => " + dataExpiracao); } } - + /// /// Extensão para retornar o número de dias válidos do certificado /// @@ -321,22 +331,33 @@ public static bool IsA3(this X509Certificate2 x509Certificate2) bool result = false; - try + /// Suprimindo o aviso CA1416 para esta região de código específica +#pragma warning disable CA1416 + if (Environment.OSVersion.Platform == PlatformID.Win32NT || Environment.OSVersion.Platform == PlatformID.Win32Windows || Environment.OSVersion.Platform == PlatformID.Win32S) { - RSACryptoServiceProvider service = x509Certificate2.PrivateKey as RSACryptoServiceProvider; - if (service != null) + try + { + RSACryptoServiceProvider service = x509Certificate2.PrivateKey as RSACryptoServiceProvider; + + if (service != null) + { + if (service.CspKeyContainerInfo.Removable && + service.CspKeyContainerInfo.HardwareDevice) + result = true; + } + } + catch { - if (service.CspKeyContainerInfo.Removable && - service.CspKeyContainerInfo.HardwareDevice) - result = true; + //assume que é false + result = false; } } - catch + else { - //assume que é false - result = false; + throw new NotSupportedException("Metodo IsA3 com suporte apenas no Windows atualmente!"); } +#pragma warning restore CA1416 return result; } diff --git a/DFe.Utils/CertificadoDigitalUtils.cs b/DFe.Utils/CertificadoDigitalUtils.cs index 25f6e5263..178f71ea8 100644 --- a/DFe.Utils/CertificadoDigitalUtils.cs +++ b/DFe.Utils/CertificadoDigitalUtils.cs @@ -90,7 +90,7 @@ public static X509Certificate2 ObterDoCaminho(string caminho, SecureString passw /// array de byte do certificado /// string representando a senha do certificado /// - public static X509Certificate2 ObterDosBytes(byte[] bytes, string password) + public static X509Certificate2 ObterDosBytes(byte[] bytes, string password, X509KeyStorageFlags? keyStorageFlags) { SecureString stringSegura = null; try @@ -104,7 +104,7 @@ public static X509Certificate2 ObterDosBytes(byte[] bytes, string password) } } - return ObterDosBytes(bytes, stringSegura); + return ObterDosBytes(bytes, stringSegura, keyStorageFlags); } catch { @@ -118,9 +118,9 @@ public static X509Certificate2 ObterDosBytes(byte[] bytes, string password) /// array de byte do certificado /// SecureString senha do certificado /// - public static X509Certificate2 ObterDosBytes(byte[] bytes, SecureString password) + public static X509Certificate2 ObterDosBytes(byte[] bytes, SecureString password, X509KeyStorageFlags? keyStorageFlags) { - var cert = new X509Certificate2(bytes, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); + var cert = new X509Certificate2(bytes, password, keyStorageFlags ?? (X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable)); return cert; } diff --git a/DFe.Utils/ConfiguracaoCertificado.cs b/DFe.Utils/ConfiguracaoCertificado.cs index d0622f432..158e28bf5 100644 --- a/DFe.Utils/ConfiguracaoCertificado.cs +++ b/DFe.Utils/ConfiguracaoCertificado.cs @@ -33,6 +33,7 @@ using System; using System.ComponentModel; +using System.Security.Cryptography.X509Certificates; namespace DFe.Utils { @@ -59,9 +60,11 @@ public class ConfiguracaoCertificado private TipoCertificado _tipoCertificado; private string _cacheId; private byte[] _arrayBytesArquivo; + private X509KeyStorageFlags _keyStorageFlags; public ConfiguracaoCertificado() { + KeyStorageFlags = X509KeyStorageFlags.MachineKeySet; SignatureMethodSignedXml = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; DigestMethodReference = "http://www.w3.org/2000/09/xmldsig#sha1"; } @@ -179,5 +182,18 @@ public string CacheId /// URI para DigestMethod na Classe Reference para auxiliar para a assinatura (Padrao: http://www.w3.org/2000/09/xmldsig#sha1) /// public string DigestMethodReference { get; set; } + + /// + /// + /// + public X509KeyStorageFlags KeyStorageFlags + { + get { return _keyStorageFlags; } + set + { + if (value == _keyStorageFlags) return; + _keyStorageFlags = value; + } + } } } diff --git a/NFe.Danfe.App.Teste.Html/NFe.Danfe.App.Teste.Html.csproj b/NFe.Danfe.App.Teste.Html/NFe.Danfe.App.Teste.Html.csproj index 5ef580f31..11ba5f138 100644 --- a/NFe.Danfe.App.Teste.Html/NFe.Danfe.App.Teste.Html.csproj +++ b/NFe.Danfe.App.Teste.Html/NFe.Danfe.App.Teste.Html.csproj @@ -8,7 +8,7 @@ - + diff --git a/NFe.Danfe.Fast.Skia/NFe.Danfe.Fast.Skia.csproj b/NFe.Danfe.Fast.Skia/NFe.Danfe.Fast.Skia.csproj index 9c45dbe7d..cdf4a3ff7 100644 --- a/NFe.Danfe.Fast.Skia/NFe.Danfe.Fast.Skia.csproj +++ b/NFe.Danfe.Fast.Skia/NFe.Danfe.Fast.Skia.csproj @@ -10,7 +10,7 @@ - + diff --git a/NFe.Danfe.Html/NFe.Danfe.Html.csproj b/NFe.Danfe.Html/NFe.Danfe.Html.csproj index 0b2c8ed26..a660375bd 100644 --- a/NFe.Danfe.Html/NFe.Danfe.Html.csproj +++ b/NFe.Danfe.Html/NFe.Danfe.Html.csproj @@ -6,7 +6,7 @@ - + diff --git a/NFe.Utils.Testes/NFe.Utils.Testes.csproj b/NFe.Utils.Testes/NFe.Utils.Testes.csproj index 1049b8121..0391c87f7 100644 --- a/NFe.Utils.Testes/NFe.Utils.Testes.csproj +++ b/NFe.Utils.Testes/NFe.Utils.Testes.csproj @@ -7,9 +7,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive