KB5025823 Alteração na forma como os aplicativos .NET importam certificados X.509

Aplica-se a
.NET

Observação: Revisado em 22 de junho de 2023 para atualizar a resolução e as soluções alternativas

Observação: Revisado em 15 de junho de 2023 para atualizar as opções 4 e 5

Antecedentes

Em 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 tempo de execução importa certificados X.509. Essas alterações podem fazer com que a importação do certificado X.509 gere CryptographicException em cenários em que a importação teria sido bem-sucedida antes da atualização.

Este documento descreve a alteração e as soluções alternativas disponíveis para os aplicativos afetados.

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

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 delegam a validação e a importação do blob para o sistema operacional subjacente. Por exemplo, no Windows, o .NET Framework e o .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 forem apresentados com um blob de certificado binário para importação, o .NET Framework e o .NET, em algumas circunstâncias, executarão uma validação adicional antes de entregar o blob ao sistema operacional 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 na importação. Como essa é uma validação adicional além do que o sistema operacional subjacente normalmente executaria, ele pode bloquear blobs de certificados que teriam sido importados com êxito antes da alteração de 13 de junho de 2023.

Regressões conhecidas

  1. Se um certificado X.509 tiver sido exportado como um blob PFX usando uma contagem de iteração de senha excepcionalmente alta, esse certificado poderá falhar ao ser importado. A maioria das instalações de exportação de certificados usa uma contagem de iterações 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ção maior que 600.000.

  2. Se um certificado X.509 tiver sido exportado usando uma senha nula [por exemplo, por meio X509Certificate.Export(X509ContentType.Pfx, (string)null) ou sem X509Certificate.Export(X509ContentType.Pfx)]senha, esse certificado poderá falhar ao ser importado.
     

    Observação

    A regressão acima foi abordada na atualização de 22 de junho de 2023 discutida em KB5028608.

  3. Se um certificado X.509 tiver sido exportado como um blob PFX usando a capacidade do Windows de proteger a chave privada em um SID, esse certificado poderá falhar ao ser importado. Isso afetará os blobs PFX criados das seguintes maneiras:

    • Por meio 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; ou
    • Por meio do cmdlet Export-PfxCertificate do PowerShell, no qual um argumento explícito -ProtectTo é fornecido; ou
    • Por meio do utilitário certutil em que um argumento explícito -protectto é fornecido; ou
    • Por meio da API PFXExportCertStoreEx em que o sinalizador PKCS12_PROTECT_TO_DOMAIN_SIDS é fornecido.

Resolução & soluções alternativas

Existem várias soluções alternativas, dependendo de você querer fazer alterações direcionadas em sites de chamada individuais dentro do seu código, alterar o comportamento de um único aplicativo ou fazer alterações em todo o computador.

Opção 1 (preferencial) - Instalar um patch atualizado

Observação

Essa é a opção preferencial, pois aborda regressões de clientes comumente relatadas e não exige nenhuma alteração de código no aplicativo.

Aplicabilidade: essa opção se aplica a todas as versões do .NET Framework e do .NET.

Esse problema foi resolvido na atualização de 22 de junho de 2023 discutida no KB5028608.

A Microsoft recomenda que os clientes que estão enfrentando regressões introduzidas pela versão de 13 de junho de 2023 tentem instalar este patch atualizado antes de tentar as soluções alternativas listadas posteriormente neste documento.

Opção 2 – Modificar o site de chamada

Aplicabilidade: essa opção se aplica a todas as versões do .NET Framework e do .NET.

Considere se o blob que você está importando é confiável. Por exemplo, o blob foi recuperado de um local confiável, como um banco de dados ou arquivo de configuração 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 que você não importe blobs PFX fornecidos a você por clientes não autenticados ou sem privilégios, pois esses blobs podem conter comportamentos mal-intencionados de esgotamento de recursos.

Se você precisar importar um blob de certificado de chave pública fornecido a você por uma parte não confiável, poderá usar o código a seguir para importar esse blob com segurança. Este código de exemplo usa o método GetCertContentType para determinar qual é o tipo subjacente do blob de certificados e rejeita blobs PFX nos casos em que você espera importar apenas um blob de certificado de chave pública. O X509Certificate2(byte[]) construtor é seguro para uso quando recebe blobs não PFX não confiáveis.


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 você precisar importar um blob de certificado de chave privada sem senha e tiver determinado que o blob é confiável, poderá suprimir as verificações de validação adicionais executadas pela versão de segurança de 13 de junho de 2023 chamando 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 usando uma variável de ambiente

Aplicabilidade: essa opção se aplica 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 aplicativo ou em todo o computador usando uma variável de ambiente. Esse novo limite se aplicará 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 o novo limite deve ser. Por exemplo, para definir o limite para 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 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 essa variável de ambiente como 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 como o valor de sentinela especial -1, conforme mostrado abaixo.

  • ⚠️ Aviso: Defina o valor da variável de ambiente como -1 apenas se tiver certeza de que o aplicativo de destino não está lidando com entrada de certificado não confiável.

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1

Opção 4 – modificar ou suprimir a validação adicional usando AppContext

Aplicabilidade: essa opção se aplica somente ao .NET 6.0+.  Não se aplica ao .NET Framework

Embora o .NET, por padrão, limite as operações de importação para não receber mais de 600.000 iterações de uma senha, esse limite pode ser configurado em todo o aplicativo usando o comutador AppContext. Esse novo limite se aplicará a todas as invocações das APIs afetadas listadas acima.

Para alterar o limite, defina o comutador AppContext System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit como o valor de qual 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 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 essa variável de ambiente como 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 opção no arquivo de projeto do aplicativo (.csproj ou .vbproj):

<!--

  • Esta opção só funcionará se o arquivo de projeto atual representar um aplicativo. Ele não terá efeito se o arquivo de projeto atual representar uma biblioteca compartilhada.

-->

<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 seu 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 as configurações do .NET Runtime da página de documentação.

Para suprimir totalmente as verificações adicionais, defina a opção de configuração com o valor de sentinela especial -1, conforme mostrado abaixo.

⚠️ Aviso: defina a opção AppContext como -1 apenas se tiver certeza de que o aplicativo de destino não está lidando com entradas de certificado não confiáveis.

No arquivo de projeto do aplicativo (.csproj ou .vbproj):

<!--

  • Esta opção só funcionará se o arquivo de projeto atual representar um aplicativo. Ele não terá efeito se o arquivo de projeto atual representar uma biblioteca compartilhada.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="-1" />

</ItemGroup>

Ou no arquivo runtimeconfig.template.json:

{

  • "configProperties": {
  • "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1

     }

}

Opção 5 – Modificar ou suprimir a validação adicional em todo o computador por meio do registro (somente Windows para o .NET Framework)

Aplicabilidade: essa opção se aplica 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.