Applies To.NET

Nota: 22 de junio de 2023 revisado para actualizar la resolución y las soluciones alternativas

Nota: 15 de junio de 2023 revisado para actualizar las opciones 4 y 5 

Fondo

El 13 de junio de 2023, Microsoft publicó una actualización de seguridad para .NET Framework y .NET que afecta a cómo importa el tiempo de ejecución los certificados X.509. Estos cambios pueden provocar que la importación de certificado X.509 inicie CryptographicException en escenarios donde la importación se habría realizado correctamente antes de la actualización.

Este documento describe el cambio y las soluciones alternativas disponibles para las aplicaciones afectadas.

Software afectado

  • .NET Framework 2.0

  • .NET Framework 4.6.2, 4.7, 4.7.1 y 4.7.2

  • .NET Framework 4.8

  • .NET Framework 4.8.1

  • .NET 6.0

  • .NET 7.0

API afectadas

Descripción del cambio

Antes del 13 de junio de 2023, el cambio, cuando .NET Framework y .NET se presentan con un blob de certificado binario para la importación, .NET Framework y .NET normalmente delegarían la validación e importación del blob en el sistema operativo subyacente. Por ejemplo, en Windows, .NET Framework y .NET normalmente se basaría en la API PFXImportCertStore para validación e importación.

A partir del 13 de junio de 2023, cambie cuando .NET Framework y .NET se presenten con un blob de certificado binario para la importación, .NET Framework y .NET realizarán en algunas circunstancias una validación adicional antes de entregar el blob al sistema operativo subyacente. Esta validación adicional realiza una serie de comprobaciones heurísticas para determinar si el certificado entrante agotaría mal los recursos al importarlo. Dado que se trata de una validación adicional más allá de lo que normalmente realizaría el SO subyacente, puede bloquear los blobs de certificados que se habrían importado correctamente antes del cambio del 13 de junio de 2023.

Regresiones conocidas

  1. Si un certificado X.509 se ha exportado como un blob PFX usando un recuento de iteraciones de contraseñas inusualmente alto, ese certificado ahora puede no importarse. La mayoría de las instalaciones de exportación de certificados usan un recuento de iteraciones entre 2.000 y 10.000. Después de aplicar la actualización de seguridad, se producirá un error en la importación de los certificados que contienen un recuento de iteraciones superior a 600 000.

  2. Si un certificado X.509 se ha exportado con una contraseña nula [por ejemplo, a través deX509Certificate.Export(X509ContentType.Pfx, (string)null)o de laX509Certificate.Export(X509ContentType.Pfx)]sin contraseña , ese certificado puede no importarse ahora.  

    Nota: La regresión anterior se ha resuelto en la actualización del 22 de junio de 2023 que se describe en KB5028608.

  3. Si un certificado X.509 se ha exportado como un blob PFX usando la capacidad de Windows para proteger la clave privada a un SID, ese certificado ahora puede no importarse. Esto afectará a los blobs PFX creados de las siguientes maneras:

    • A través del Asistente para exportación de certificados de Windows y especificando en el asistente que la clave privada debe estar protegida para un usuario de dominio; O

    • A través del cmdlet Export-PfxCertificate de PowerShell donde se proporciona un argumento de -ProtectTo explícito; O

    • A través de la utilidad certutil donde se proporciona un argumento de -protectto explícito; O

    • A través de la API PFXExportCertStoreEx donde se proporciona la marca de PKCS12_PROTECT_TO_DOMAIN_SIDS.

Solución & soluciones alternativas

Existen varias soluciones alternativas, dependiendo de si desea realizar cambios específicos en sitios de llamadas individuales dentro de su código, o desea cambiar el comportamiento de una sola aplicación, o desea realizar cambios en toda la máquina.

Opción 1 (preferida): instalar una revisión actualizada

Nota: Esta es la opción preferida, ya que corrige las regresiones de cliente notificadas habitualmente y no requiere cambios de código en la aplicación.

Aplicabilidad: esta opción se aplica a todas las versiones de .NET Framework y .NET.

Este problema se ha resuelto en la actualización del 22 de junio de 2023 que se describe en KB5028608.

Microsoft recomienda que los clientes que experimentan regresiones introducidas el 13 de junio de 2023 intenten instalar esta revisión actualizada antes de intentar las soluciones alternativas enumeradas más adelante en este documento.

Opción 2: Modificar el sitio de llamada

Aplicabilidad: esta opción se aplica a todas las versiones de .NET Framework y .NET.

Considere si el blob que está importando es de confianza. Por ejemplo, ¿se ha recuperado el blob de una ubicación de confianza, como una base de datos o un archivo de configuración bajo su control, o se ha proporcionado a través de una solicitud de red realizada por un cliente sin autenticar o sin privilegios?

Microsoft recomienda encarecidamente que no importe blobs PFX proporcionados por clientes sin autenticar o sin privilegios, ya que estos blobs podrían contener comportamientos malintencionados de agotamiento de recursos.

Si necesita importar un blob de certificado de clave pública que le haya proporcionado un tercero que no es de confianza, puede usar el siguiente código para importar dicho blob de forma segura. En este código de ejemplo se usa el método GetCertContentType para determinar cuál es el tipo subyacente del blob de certificados y se rechazan los blobs PFX en los casos en los que solo se espera importar un blob de certificado de clave pública. El constructor deX509Certificate2(byte[]) es seguro para su uso cuando se dan blobs no PFX que no son de confianza.

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);
    }
} 

Si necesita importar un blob de certificado de clave privada sin contraseña y ha determinado que el blob es de confianza, puede suprimir las comprobaciones de validación adicionales realizadas por la versión de seguridad del 13 de junio de 2023 llamando a una sobrecarga de constructor diferente. Por ejemplo, puede llamar a la sobrecarga del constructor que acepta un argumento de contraseña de cadena y pasa null para el valor del 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);

Opción 3: Modificar o suprimir la validación adicional con una variable de entorno

Aplicabilidad: esta opción se aplica solo a todas las versiones de .NET Framework.  No se aplica a .NET 6.0 y posterior.

Mientras que .NET Framework limita de forma predeterminada las operaciones de importación para no más de 600 000 iteraciones de una contraseña, este límite se puede configurar en toda la aplicación o en toda la máquina mediante una variable de entorno. Este nuevo límite se aplicará a todas las invocaciones de las API afectadas enumeradas anteriormente.

Para cambiar el límite, establezca la variable de entornoCOMPlus_Pkcs12UnspecifiedPasswordIterationLimital valor de lo que debe ser el nuevo límite. Por ejemplo, para establecer el límite en 1.000.000 iteraciones (un millón), establezca la variable de entorno como se muestra a continuación.

  • Este número controla el límite de iteraciones totales , que es la suma del recuento de iteraciones de MAC, el contenido seguro cifrado y el recuento de iteraciones de bolsa cubierta. Si ha exportado manualmente un PFX mediante un recuento de iteraciones explícitas <iter_count> (por ejemplo, a través de openssl pkcs12 -export -iter <iter_count>) y desea importar ese blob PFX, establezca esta variable de entorno en un valor al menos tan grande como la suma de todas las iteraciones esperadas. En la práctica, .NET Framework y .NET pueden permitir que el recuento de iteraciones totales supere ligeramente cualquier límite explícito configurado aquí.

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000

Para suprimir las comprobaciones adicionales por completo, establezca la variable de entorno en el valor de centinela especial -1, como se muestra a continuación.

  • ⚠️ Advertencia: Establezca solo el valor de la variable de entorno en -1 si está seguro de que la aplicación de destino no controla la entrada de certificados que no son de confianza.

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1

Opción 4: Modificar o suprimir la validación adicional con AppContext

Aplicabilidad: esta opción se aplica solo a .NET 6.0 y posterior.  No se aplica a .NET Framework

Aunque .NET limita de forma predeterminada las operaciones de importación a no más de 600 000 iteraciones de una contraseña, este límite se puede configurar en toda la aplicación mediante el modificador AppContext. Este nuevo límite se aplicará a todas las invocaciones de las API afectadas enumeradas anteriormente.

Para cambiar el límite, establezca el modificador AppContext System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit por el valor del nuevo límite. Por ejemplo, para establecer el límite en 1.000.000 iteraciones (un millón), establezca el conmutador como se muestra a continuación.

  • Este número controla el límite de iteraciones totales, que es la suma del recuento de iteraciones de MAC, el contenido seguro cifrado y el recuento de iteraciones de bolsa cubierta. Si ha exportado manualmente un PFX mediante un recuento de iteraciones explícitas <iter_count> (por ejemplo, a través de openssl pkcs12 -export -iter <iter_count>) y desea importar ese blob PFX, establezca esta variable de entorno en un valor al menos tan grande como la suma de todas las iteraciones esperadas. En la práctica, .NET puede permitir que el recuento de iteraciones totales supere ligeramente cualquier límite explícito configurado aquí.

Para establecer el modificador dentro del archivo de proyecto de la aplicación (.csproj o .vbproj):

<!--

  • This switch only works if the current project file represents an application. It has no effect if the current project file represents a shared library.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="1000000" />

</ItemGroup>

Como alternativa, puede colocar un archivo denominado runtimeconfig.template.json con el siguiente contenido en el mismo directorio que contiene el archivo de proyecto de la aplicación:

{

     "configProperties": {

  • "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000

      }

}

Para obtener más información sobre cómo cambiar la configuración de tiempo de ejecución de .NET, consulta la página de documentación Configuración de tiempo de ejecución de .NET.

Para suprimir las comprobaciones adicionales por completo, configure el valor del centinela especial -1, tal y como se muestra a continuación.

⚠️ Advertencia: Establezca solo el modificador AppContext en -1 si está seguro de que la aplicación de destino no controla la entrada de certificados que no son de confianza.

Dentro del archivo de proyecto de la aplicación (.csproj o .vbproj):

<!--

  • This switch only works if the current project file represents an application. It has no effect if the current project file represents a shared library.

-->

<ItemGroup>

  • <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="-1" />

</ItemGroup>

O en el archivo runtimeconfig.template.json:

{

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

     }

}

Opción 5: Modificar o suprimir la validación adicional en todo el equipo a través del Registro (Windows-only para .NET Framework)

Aplicabilidad: esta opción se aplica solo a todas las versiones de .NET Framework.  No se aplica a .NET 6.0 y posterior.

Aunque .NET Framework limita de forma predeterminada las operaciones de importación a no más de 600 000 iteraciones de una contraseña, este límite se puede configurar en todo el equipo mediante el Registro HKLM. Este nuevo límite se aplicará a todas las invocaciones de las API afectadas enumeradas anteriormente.

Para cambiar el límite, en la clave del RegistroHKLM\Software\Microsoft\.NETFramework, establezca el valorPkcs12UnspecifiedPasswordIterationLimiten el nuevo límite. Por ejemplo, para establecer el límite en 1.000.000 (un millón) de iteraciones, ejecute los comandos como se muestra a continuación desde un símbolo del sistema con privilegios elevados.

  • Este número controla el límite de iteraciones totales , que es la suma del recuento de iteraciones de MAC, el contenido seguro cifrado y el recuento de iteraciones de bolsa cubierta. Si ha exportado manualmente un PFX mediante un recuento de iteraciones explícitas <iter_count> (por ejemplo, a través de openssl pkcs12 -export -iter <iter_count>) y desea importar ese blob PFX, establezca este valor del Registro en un valor al menos tan grande como la suma de todas las iteraciones esperadas. En la práctica, .NET Framework puede permitir que el recuento de iteraciones totales supere ligeramente cualquier límite explícito configurado aquí.

  • La configuración del Registro depende de la arquitectura. Para asegurarse de que las aplicaciones observen el valor configurado independientemente de su arquitectura de destino, recuerde modificar los registros de 32 bits y 64 bits, como se muestra a continuación.

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 las comprobaciones adicionales por completo, establezca el valor del Registro en -1 desde un símbolo del sistema con privilegios elevados, como se muestra a continuación.

  • ⚠️ Advertencia: Establezca solo el valor del Registro en -1 si está seguro de que los servicios que se ejecutan en el equipo de destino no administran la entrada de certificados que no son de confianza.

  • Para establecer el centinela -1, use el tipo de REG_SZ en lugar del tipo REG_DWORD. La configuración del Registro depende de la arquitectura. Para asegurarse de que las aplicaciones observen el valor configurado independientemente de su arquitectura de destino, recuerde modificar los registros de 32 bits y 64 bits, como se muestra a continuación.

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 revertir los cambios del Registro, elimine el valor del registro Pkcs12UnspecifiedPasswordIterationLimit de un símbolo del sistema con privilegios elevados.

reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32 reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64

Notas específicas de Windows

En Windows, .NET Framework importa los certificados a través de la función PFXImportCertStore. Esta función realiza su propia validación, incluida la colocación de sus propios límites en el número máximo de iteraciones permitidas de un blob de PFX. Estos controles se seguirán realizando tras la importación de PFX. El. Las variables de entorno específicas de NET y las claves del Registro descritas anteriormente no afectan a cómo PFXImportCertStore realiza estas comprobaciones.

¿Necesita más ayuda?

¿Quiere más opciones?

Explore las ventajas de las suscripciones, examine los cursos de aprendizaje, aprenda a proteger su dispositivo y mucho más.

Las comunidades le ayudan a formular y responder preguntas, enviar comentarios y leer a expertos con conocimientos extensos.