Skip to content

Commit

Permalink
feito nova configuracao para passar o X509KeyStorageFlags ao gerar in…
Browse files Browse the repository at this point in the history
…stancia de X509Certificate2 usando byte como certificado em memória, o mesmo funciona para certificados em arquivos. O problema resolve se você estiver enfrentando problemas relacionados a permissões de acesso ao carregar certificados, pode ser útil usar X509KeyStorageFlags.EphemeralKeySet que é possível em .net 6 + (#1473)
  • Loading branch information
danilobreda authored Jan 16, 2024
1 parent 7c320a5 commit b54eaa8
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 48 deletions.
11 changes: 7 additions & 4 deletions DFe.Testes/DFe.Testes.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.7" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.7" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
89 changes: 55 additions & 34 deletions DFe.Utils/Assinatura/CertificadoDigital.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ public static X509Store ObterX509Store(OpenFlags openFlags)
/// <param name="arquivo">Arquivo do certificado digital</param>
/// <param name="senha">Senha do certificado digital</param>
/// <returns></returns>
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;
}

Expand All @@ -85,11 +85,11 @@ private static X509Certificate2 ObterDeArquivo(string arquivo, string senha)
/// <param name="arrayBytes">Array de bytes do certificado digital</param>
/// <param name="senha">Senha do certificado digital</param>
/// <returns></returns>
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)
Expand Down Expand Up @@ -148,24 +148,34 @@ private static X509Certificate2 ObterDoRepositorioPassandoPin(string serial, str
/// </summary>
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;

Check warning on line 156 in DFe.Utils/Assinatura/CertificadoDigital.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

'X509Certificate2.PrivateKey' is obsolete: 'X509Certificate2.PrivateKey is obsolete. Use the appropriate method to get the private key, such as GetRSAPrivateKey, or use the CopyWithPrivateKey method to create a new instance with a private key.'

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
}

/// <summary>
Expand All @@ -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:
Expand Down Expand Up @@ -294,7 +304,7 @@ public static void VerificaValidade(this X509Certificate2 x509Certificate2)
throw new ArgumentException("Certificado digital vencido na data => " + dataExpiracao);
}
}

/// <summary>
/// Extensão para retornar o número de dias válidos do certificado
/// </summary>
Expand All @@ -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;

Check warning on line 341 in DFe.Utils/Assinatura/CertificadoDigital.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

'X509Certificate2.PrivateKey' is obsolete: 'X509Certificate2.PrivateKey is obsolete. Use the appropriate method to get the private key, such as GetRSAPrivateKey, or use the CopyWithPrivateKey method to create a new instance with a private key.'

Check warning on line 341 in DFe.Utils/Assinatura/CertificadoDigital.cs

View workflow job for this annotation

GitHub Actions / build (windows-2022)

'X509Certificate2.PrivateKey' is obsolete: 'X509Certificate2.PrivateKey is obsolete. Use the appropriate method to get the private key, such as GetRSAPrivateKey, or use the CopyWithPrivateKey method to create a new instance with a private key.'

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;
}
Expand Down
8 changes: 4 additions & 4 deletions DFe.Utils/CertificadoDigitalUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static X509Certificate2 ObterDoCaminho(string caminho, SecureString passw
/// <param name="bytes">array de byte do certificado</param>
/// <param name="password">string representando a senha do certificado</param>
/// <returns></returns>
public static X509Certificate2 ObterDosBytes(byte[] bytes, string password)
public static X509Certificate2 ObterDosBytes(byte[] bytes, string password, X509KeyStorageFlags? keyStorageFlags)
{
SecureString stringSegura = null;
try
Expand All @@ -104,7 +104,7 @@ public static X509Certificate2 ObterDosBytes(byte[] bytes, string password)
}
}

return ObterDosBytes(bytes, stringSegura);
return ObterDosBytes(bytes, stringSegura, keyStorageFlags);
}
catch
{
Expand All @@ -118,9 +118,9 @@ public static X509Certificate2 ObterDosBytes(byte[] bytes, string password)
/// <param name="bytes">array de byte do certificado</param>
/// <param name="password">SecureString senha do certificado</param>
/// <returns></returns>
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;
}

Expand Down
16 changes: 16 additions & 0 deletions DFe.Utils/ConfiguracaoCertificado.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

using System;
using System.ComponentModel;
using System.Security.Cryptography.X509Certificates;

namespace DFe.Utils
{
Expand All @@ -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";
}
Expand Down Expand Up @@ -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)
/// </summary>
public string DigestMethodReference { get; set; }

/// <summary>
///
/// </summary>
public X509KeyStorageFlags KeyStorageFlags
{
get { return _keyStorageFlags; }
set
{
if (value == _keyStorageFlags) return;
_keyStorageFlags = value;
}
}
}
}
2 changes: 1 addition & 1 deletion NFe.Danfe.App.Teste.Html/NFe.Danfe.App.Teste.Html.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Zeus.Net.NFe.NFCe" Version="2023.6.7.1227" />
<PackageReference Include="Zeus.Net.NFe.NFCe" Version="2024.1.15.1723" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion NFe.Danfe.Fast.Skia/NFe.Danfe.Fast.Skia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="SkiaSharp" Version="2.88.3" />
<PackageReference Include="SkiaSharp" Version="2.88.7" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion NFe.Danfe.Html/NFe.Danfe.Html.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<ItemGroup>
<PackageReference Include="NetBarcode" Version="1.7.0" />
<PackageReference Include="Zeus.Net.NFe.NFCe" Version="2023.6.7.1227" />
<PackageReference Include="Zeus.Net.NFe.NFCe" Version="2024.1.15.1723" />
</ItemGroup>

<ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions NFe.Utils.Testes/NFe.Utils.Testes.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down

0 comments on commit b54eaa8

Please sign in to comment.