Observação: Revisado em 22 de junho de 2023 para atualizar a resolução e as soluções alternativas
Observação: Atualização de 15 de junho de 2023 para atualizar a solução alternativa opções 4 e 5
Contexto geral
A 13 de junho de 2023, a Microsoft lançou uma atualização de segurança para o .NET Framework e o .NET que afeta a forma como o runtime importa certificados X.509. Estas alterações podem fazer com que a importação de certificado X.509 gere CryptographicException em cenários em que a importação teria sido efetuada com êxito antes da atualização.
Este documento descreve as alterações e as soluções alternativas disponíveis para as aplicações afetadas.
Software afetado
- .NET Framework 2.0
- .NET Framework 4.6.2, 4.7, 4.7.1, 4.7.2
- .NET Framework 4.8
- .NET Framework 4.8.1
- .NET 6.0
- .NET 7.0
APIs afetadas
- novo X509Certificate(byte[])
- X509Certificate.Import(byte[])
- novo X509Certificate2(byte[])
- X509Certificate2.Import(byte[])
- X509Certificate2Collection.Import(byte[])
Descrição da alteração
Antes da alteração de 13 de junho de 2023, quando o .NET Framework e o .NET são apresentados com um blob de certificado binário para importação, o .NET Framework e o .NET normalmente delegavam a validação e a importação do blob ao SO subjacente. Por exemplo, no Windows, .NET Framework e .NET normalmente dependeriam da API PFXImportCertStore para validação e importação.
A partir da alteração de 13 de junho de 2023, quando o .NET Framework e o .NET receberem um blob de certificado binário para importação, o .NET Framework e o .NET irão, em algumas circunstâncias, executar validação adicional antes de entregar o blob ao SO subjacente. Essa validação adicional executa uma série de verificações heurísticas para determinar se o certificado de entrada esgotaria maliciosamente os recursos durante a importação. Uma vez que esta é uma validação adicional além do que o SO subjacente normalmente executaria, pode bloquear blobs de certificado que teriam sido importados com êxito antes da alteração de 13 de junho de 2023.
Regressões conhecidas
Se um certificado X.509 tiver sido exportado como um blob PFX utilizando uma contagem de iteração de palavra-passe invulgarmente alta, esse certificado poderá agora falhar ao importar. A maioria das instalações de exportação de certificados usa uma contagem de iteração entre 2.000 e 10.000. Depois que a atualização de segurança for aplicada, a importação falhará para certificados contendo uma contagem de iterações maior que 600.000.
Se um certificado X.509 tiver sido exportado utilizando uma palavra-passe nula [por exemplo, através
X509Certificate.Export(X509ContentType.Pfx, (string)null)ou sem palavra-passeX509Certificate.Export(X509ContentType.Pfx)], esse certificado pode agora falhar na importação.
Observação
A regressão acima foi corrigida na Atualização de 22 de junho de 2023 debatida no KB5028608.
Se um certificado X.509 tiver sido exportado como um blob PFX utilizando a capacidade do Windows para proteger a chave privada de um SID, esse certificado poderá agora falhar na importação. Isto afetará os blobs PFX criados das seguintes formas:
- Através do Assistente de Exportação de Certificados do Windows e especificando no assistente que a chave privada deve ser protegida para um usuário de domínio; quer
- Através do cmdlet Export-PfxCertificate do PowerShell onde é fornecido um argumento explícito
-ProtectTo; ou - Através do utilitário certutil onde um argumento explícito
-protecttoé fornecido; - Através da API PFXExportCertStoreEx , onde o sinalizador de PKCS12_PROTECT_TO_DOMAIN_SIDS é fornecido.
Resolução & Soluções
Existem várias soluções alternativas, dependendo se você deseja fazer alterações direcionadas em sites de chamadas individuais dentro do código, ou deseja alterar o comportamento de um único aplicativo, ou deseja fazer alterações em toda a máquina.
Opção 1 (preferencial) - Instalar uma correção atualizada
Observação
Esta é a opção preferida, pois aborda regressões de clientes relatadas com frequência e não requer nenhuma alteração de código para o aplicativo.
Aplicabilidade: Esta opção aplica-se a todas as versões do .NET Framework e do .NET.
Este problema foi resolvido na Atualização de 22 de junho de 2023 debatida no KB5028608.
A Microsoft recomenda que os clientes que estão a experimentar regressões introduzidas até ao lançamento de 13 de junho de 2023 experimentem instalar este patch atualizado antes de tentarem as soluções listadas mais tarde neste documento.
Opção 2 – modificar o site de chamada
Aplicabilidade: Esta opção aplica-se a todas as versões do .NET Framework e do .NET.
Pondere se o blob que está a importar é fidedigno. Por exemplo, o blob foi recuperado de um local confiável, como um arquivo de configuração ou banco de dados sob seu controle, ou foi fornecido por meio de uma solicitação de rede feita por um cliente não autenticado ou sem privilégios?
A Microsoft recomenda vivamente que não importe blobs PFX fornecidos por clientes não autenticados ou sem privilégios, uma vez que estes blobs podem conter comportamentos maliciosos de esgotamento de recursos.
Se precisar de importar um blob de certificado de chave pública que lhe foi fornecido por uma entidade não fidedigna, pode utilizar o seguinte código para importar esse blob em segurança. Este código de exemplo usa o método GetCertContentType para determinar qual é o tipo subjacente do blob de certificado e rejeita blobs PFX nos casos em que você só espera importar um blob de certificado de chave pública. O X509Certificate2(byte[]) construtor é seguro para uso quando dado não confiáveis blobs não-PFX.
using System.Security.Cryptography.X509Certificates;
public static X509Certificate2 ImportPublicCertificateBlob(byte[] blob)
{
if (X509Certificate2.GetCertContentType(blob) == X509ContentType.Pfx)
{
throw new Exception("PFX blobs are disallowed.");
}
else
{
// Import only after we have confirmed it's not a PFX.
return new X509Certificate2(blob);
}
}
Se precisar de importar um blob de certificado de chave privada sem palavras-passe e tiver determinado que o blob é fidedigno, pode suprimir as verificações de validação adicionais realizadas até ao lançamento de segurança de 13 de junho de 2023 ao chamar uma sobrecarga de construtor diferente. Por exemplo, você pode chamar a sobrecarga do construtor que aceita um argumento de senha de cadeia de caracteres e passar null para o valor do argumento.
byte[] blobToImport = GetBlobToImport(); // fetch this from a database, config, etc.
// REGRESSION - byte[] ctor performs additional security checks X509Certificate2 certA = new X509Certificate2(blobToImport);
// RECOMMENDED WORKAROUND - different ctor overload suppresses additional security checks X509Certificate2 certB = new X509Certificate2(blobToImport, (string)null);
Opção 3 – Modificar ou suprimir a validação adicional utilizando uma variável de ambiente
Aplicabilidade: Esta opção aplica-se apenas a todas as versões do .NET Framework. Não se aplica ao .NET 6.0+.
Embora .NET Framework por padrão limitem as operações de importação para não executar mais de 600.000 iterações de uma senha, esse limite pode ser configurado em todo o aplicativo ou em toda a máquina usando uma variável de ambiente. Este novo limite será aplicado a todas as invocações das APIs Afetadas listadas acima.
Para alterar o limite, defina a variável COMPlus_Pkcs12UnspecifiedPasswordIterationLimit de ambiente com o valor do que deve ser o novo limite. Por exemplo, para definir o limite de 1.000.000 (um milhão) de iterações, defina a variável de ambiente conforme mostrado abaixo.
- Esse número controla o limite total de iteração, que é a soma da contagem de iterações MAC, conteúdo seguro criptografado e contagem de iteração do saco encoberto. Se você exportou manualmente um PFX usando um iter_count> explícito de contagem de iteração <(por exemplo, via openssl pkcs12 -export -iter <iter_count>) e deseja importar esse blob PFX, defina essa variável de ambiente para um valor pelo menos tão grande quanto a soma de todas as iterações esperadas. Na prática, o .NET Framework e o .NET podem permitir que a contagem total de iterações exceda ligeiramente qualquer limite explícito configurado aqui.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000
Para suprimir totalmente as verificações adicionais, defina a variável de ambiente para o valor sentinela especial -1, como mostrado abaixo.
- ⚠️ Aviso: defina apenas o valor da variável de ambiente como -1 se tiver certeza de que o aplicativo de destino não está lidando com entradas de certificados não confiáveis.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1
Opção 4 – Modificar ou suprimir a validação adicional utilizando AppContext
Aplicabilidade: Esta opção aplica-se apenas ao .NET 6.0+. Não se aplica a .NET Framework
Enquanto o .NET, por padrão, limita as operações de importação para não tomar mais de 600.000 iterações de uma senha, esse limite pode ser configurado em todo o aplicativo usando a opção AppContext. Este novo limite será aplicado a todas as invocações das APIs Afetadas listadas acima.
Para alterar o limite, defina a opção AppContext System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit para o valor do que deve ser o novo limite. Por exemplo, para definir o limite para 1.000.000 (um milhão) de iterações, defina a opção conforme mostrado abaixo.
- Esse número controla o limite total de iteração, que é a soma da contagem de iterações MAC, conteúdo seguro criptografado e contagem de iteração do saco encoberto. Se você exportou manualmente um PFX usando um iter_count> explícito de contagem de iteração <(por exemplo, via openssl pkcs12 -export -iter <iter_count>) e deseja importar esse blob PFX, defina essa variável de ambiente para um valor pelo menos tão grande quanto a soma de todas as iterações esperadas. Na prática, o .NET pode permitir que a contagem total de iterações exceda ligeiramente qualquer limite explícito configurado aqui.
Para definir a mudança no arquivo de projeto do aplicativo (.csproj ou .vbproj):
<!--
- Essa opção só funciona se o arquivo de projeto atual representar um aplicativo. Não terá efeito se o ficheiro de projeto atual representar uma biblioteca partilhada.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="1000000" />
</ItemGroup>
Como alternativa, você pode colocar um arquivo chamado runtimeconfig.template.json com o seguinte conteúdo no mesmo diretório que contém o arquivo de projeto do aplicativo:
{
"configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000
}
}
Para obter mais informações sobre como alterar as definições de configuração do .NET Runtime, consulte a página de documentação sobre as definições de configuração do .NET Runtime.
Para suprimir totalmente as verificações adicionais, defina o parâmetro de configuração para o valor sentinela especial -1, conforme mostrado abaixo.
⚠️ Aviso: defina a opção AppContext apenas como -1 se tiver certeza de que o aplicativo de destino não está lidando com entradas de certificados não confiáveis.
Dentro do arquivo de projeto do aplicativo (.csproj ou .vbproj):
<!--
- Essa opção só funciona se o arquivo de projeto atual representar um aplicativo. Não terá efeito se o ficheiro de projeto atual representar uma biblioteca partilhada.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="-1" />
</ItemGroup>
Em alternativa, no ficheiro runtimeconfig.template.json:
{
- "configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1
}
}
Opção 5 – Modificar ou suprimir a validação adicional em toda a máquina através do registo (apenas para Windows para .NET Framework)
Aplicabilidade: Esta opção aplica-se apenas a todas as versões do .NET Framework. Não se aplica ao .NET 6.0+.
Embora o .NET Framework, por padrão, limite as operações de importação para receber no máximo 600.000 iterações de uma senha, esse limite pode ser configurado em todo o computador usando o Registro HKLM. Esse novo limite se aplicará a todas as invocações das APIs afetadas listadas acima.
Para alterar o limite, na chave HKLM\Software\Microsoft\.NETFrameworkdo Registro, defina o valor Pkcs12UnspecifiedPasswordIterationLimit como o novo limite. Por exemplo, para definir o limite para 1.000.000 (um milhão) de iterações, execute os comandos conforme mostrado abaixo em um prompt de comando com privilégios elevados.
- Esse número controla o limite total de iteração, que é a soma da contagem de iterações do MAC, do conteúdo seguro criptografado e da contagem de iterações do saco oculto. Se você exportou manualmente um PFX usando uma contagem <de iterações explícita iter_count> (por exemplo, via openssl pkcs12 -export -iter <iter_count>) e deseja importar esse blob PFX, defina esse valor do registro como um valor pelo menos tão grande quanto a soma de todas as iterações esperadas. Na prática, o .NET Framework pode permitir que a contagem total de iterações exceda ligeiramente qualquer limite explícito configurado aqui.
- A configuração do Registro depende da arquitetura. Para garantir que os aplicativos observem o valor configurado independentemente da arquitetura de destino, lembre-se de modificar os registros de 32 bits e de 64 bits, conforme mostrado abaixo.
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_DWORD /d 1000000 /reg:32
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_DWORD /d 1000000 /reg:64
Para suprimir totalmente as verificações adicionais, defina o valor do Registro como -1 em um prompt de comando com privilégios elevados, conforme mostrado abaixo.
- ⚠️ Aviso: Defina o valor do registro como -1 apenas se tiver certeza de que os serviços em execução no computador de destino não estão lidando com entradas de certificados não confiáveis.
- Para definir o sentinela -1, use o tipo REG_SZ em vez do tipo REG_DWORD. A configuração do Registro depende da arquitetura. Para garantir que os aplicativos observem o valor configurado independentemente da arquitetura de destino, lembre-se de modificar os registros de 32 bits e de 64 bits, conforme mostrado abaixo.
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_SZ /d -1 /reg:32
reg add "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /t REG_SZ /d -1 /reg:64
Para reverter as alterações do registro, exclua o valor reg Pkcs12UnspecifiedPasswordIterationLimit em um prompt de comando com privilégios elevados.
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64
Anotações específicas do Windows
No Windows, o .NET Framework importa certificados por meio da função PFXImportCertStore. Essa função executa sua própria validação, incluindo a colocação de seus próprios limites na contagem máxima de iterações permitidas de um blob PFX. Essas verificações ainda ocorrerão na importação de PFX. O arquivo . As variáveis de ambiente específicas do NET e as chaves do Registro descritas acima não afetam a forma como a PFXImportCertStore executa essas verificações.