Opmerking: Herzien op 22 juni 2023 om de oplossing en tijdelijke oplossingen bij te werken
Opmerking: Herzien op 15 juni 2023 om werk rond opties 4 en 5 bij te werken
Achtergrond
Op 13 juni 2023 heeft Microsoft een beveiligingsupdate uitgebracht voor .NET Framework en .NET, die van invloed is op hoe de runtime X.509-certificaten importeert. Deze wijzigingen kunnen ertoe leiden dat het importeren van X.509-certificaten CryptographicException genereert in scenario's waarin het importeren vóór de update zou zijn geslaagd.
In dit document worden de wijzigingen en tijdelijke oplossingen beschreven die beschikbaar zijn voor betrokken toepassingen.
Betrokken software
-
.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
Betrokken API's
Beschrijving van de wijziging
Vóór de wijziging van 13 juni 2023, wanneer .NET Framework en .NET wordt gepresenteerd met een binaire certificaat-blob voor import, .NET Framework en .NET doorgaans validatie en import van de blob delegeren naar het onderliggende besturingssysteem. In Windows zouden .NET Framework en .NET bijvoorbeeld doorgaans afhankelijk zijn van de PFXImportCertStore-API voor validatie en importeren.
Vanaf 13 juni 2023, wanneer .NET Framework en .NET wordt gepresenteerd met een binaire certificaat-blob voor import, zullen .NET Framework en .NET in sommige omstandigheden extra validatie uitvoeren voordat de blob aan het onderliggende besturingssysteem wordt overhandigd. Deze extra validatie voert een reeks heuristische controles uit om te bepalen of het binnenkomende certificaat resources bij het importeren kwaadwillig zou uitputten. Omdat dit een extra validatie is die verder gaat dan wat het onderliggende besturingssysteem normaal gesproken zou uitvoeren, kan het certificaatblobs blokkeren die vóór 13 juni 2023 zouden zijn geïmporteerd.
Bekende regressies
-
Als een X.509-certificaat is geëxporteerd als een PFX-blob met een soms hoog aantal wachtwoord-iteraties, kan dat certificaat nu mogelijk niet worden geïmporteerd. De meeste exportfaciliteiten voor certificaten gebruiken een iteratieaantal tussen 2000 en 10.000. Nadat de beveiligingsupdate is toegepast, mislukt het importeren van certificaten met een iteratieaantal van meer dan 600.000.
-
Als een X.509-certificaat is geëxporteerd met behulp van een null-wachtwoord [bijvoorbeeld viaX509Certificate.Export(X509ContentType.Pfx, (string)null)of het wachtwoordlozeX509Certificate.Export(X509ContentType.Pfx)]), kan dat certificaat nu mogelijk niet worden geïmporteerd.
Opmerking: De bovenstaande regressie is behandeld in de update van 22 juni 2023 die wordt besproken in KB5028608.
-
Als een X.509-certificaat is geëxporteerd als een PFX-blob met de mogelijkheid van Windows om de persoonlijke sleutel te beveiligen voor een SID, kan dat certificaat nu mogelijk niet worden geïmporteerd. Dit is van invloed op PFX-blobs die op de volgende manieren zijn gemaakt:
-
Via de wizard Certificaat exporteren van Windows en in de wizard opgeven dat de persoonlijke sleutel moet worden beveiligd voor een domeingebruiker; Of
-
Via de Cmdlet Export-PfxCertificate van PowerShell waar een expliciet -ProtectTo argument wordt opgegeven; Of
-
Via het hulpprogramma certutil waar een expliciet -protectto argument wordt verstrekt; Of
-
Via de PFXExportCertStoreEx-API waar de vlag PKCS12_PROTECT_TO_DOMAIN_SIDS wordt opgegeven.
-
Tijdelijke oplossingen &
Er bestaan verschillende tijdelijke oplossingen, afhankelijk van of u gerichte wijzigingen wilt aanbrengen op afzonderlijke aanroepende sites in uw code, of dat u het gedrag van één toepassing wilt wijzigen of dat u machinebrede wijzigingen wilt aanbrengen.
Optie 1 (voorkeur) - Een bijgewerkte patch installeren
Opmerking: Dit is de voorkeursoptie omdat hiermee veelvoorkomende klantregressies worden aangepakt en er geen codewijzigingen in de toepassing nodig zijn.
Toepasselijkheid: deze optie is van toepassing op alle versies van .NET Framework en .NET.
Dit probleem is opgelost in de update van 22 juni 2023 die wordt besproken in KB5028608.
Microsoft raadt klanten die regressies ondervinden die zijn geïntroduceerd op de release van 13 juni 2023, aan deze bijgewerkte patch te installeren voordat ze de tijdelijke oplossingen proberen die verderop in dit document worden vermeld.
Optie 2: de aanroepsite wijzigen
Toepasselijkheid: deze optie is van toepassing op alle versies van .NET Framework en .NET.
Overweeg of de blob die u importeert betrouwbaar is. Is de blob bijvoorbeeld opgehaald van een vertrouwde locatie, zoals een database of configuratiebestand onder uw beheer, of is deze verstrekt via een netwerkaanvraag die is ingediend door een niet-geverifieerde of niet-gemachtigde client?
Microsoft raadt u ten zeerste aan geen PFX-blobs te importeren die u hebt geleverd door niet-geverifieerde of niet-gemachtigde clients, omdat deze blobs schadelijk gedrag van resource-uitputting kunnen bevatten.
Als u een openbare-sleutelcertificaat-blob wilt importeren die u hebt gekregen van een niet-vertrouwde partij, kunt u de volgende code gebruiken om een dergelijke blob veilig te importeren. Deze voorbeeldcode maakt gebruik van de methode GetCertContentType om te bepalen wat het onderliggende type van de certificaat-blob is. Pfx-blobs worden geweigerd in gevallen waarin u alleen verwacht een openbare-sleutelcertificaatblob te importeren. DeX509Certificate2(byte[]) constructor is veilig voor gebruik bij niet-vertrouwde niet-PFX-blobs.
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);
}
}
Als u een persoonlijke-sleutelcertificaatblob zonder wachtwoord wilt importeren en u hebt vastgesteld dat de blob betrouwbaar is, kunt u de extra validatiecontroles onderdrukken die zijn uitgevoerd door de beveiligingsrelease van 13 juni 2023 door een andere constructor-overbelasting aan te roepen. U kunt bijvoorbeeld de constructor-overbelasting aanroepen die een tekenreekswachtwoordargument accepteert en null doorgeven voor de argumentwaarde.
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);
Optie 3: de aanvullende validatie wijzigen of onderdrukken met behulp van een omgevingsvariabele
Toepasselijkheid: deze optie is alleen van toepassing op alle versies van .NET Framework. Dit is niet van toepassing op .NET 6.0+.
Hoewel .NET Framework standaard importbewerkingen beperken tot maximaal 600.000 iteraties van een wachtwoord, kan deze limiet worden geconfigureerd op app- of machinebrede basis met behulp van een omgevingsvariabele. Deze nieuwe limiet is van toepassing op alle aanroepen van de betrokken API's die hierboven worden vermeld.
Als u de limiet wilt wijzigen, stelt u de omgevingsvariabeleCOMPlus_Pkcs12UnspecifiedPasswordIterationLimitin op de waarde van wat de nieuwe limiet moet zijn. Als u bijvoorbeeld de limiet wilt instellen op 1.000.000 (één miljoen) iteraties, stelt u de omgevingsvariabele in, zoals hieronder wordt weergegeven.
-
Dit getal bepaalt de totale iteratielimiet. Dit is de som van het aantal MAC-iteraties, de versleutelde veilige inhoud en het iteratieaantal van de gehulde zak. Als u handmatig een PFX hebt geëxporteerd met behulp van een expliciet aantal iteraties <iter_count> (bijvoorbeeld via openssl pkcs12 -export -iter <iter_count>) en die PFX-blob wilt importeren, stelt u deze omgevingsvariabele in op een waarde die minstens zo groot is als de som van alle verwachte iteraties. In de praktijk kunnen .NET Framework en .NET toestaan dat het totale iteratieaantal enigszins de expliciete limiet overschrijdt die hier is geconfigureerd.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000
Als u de aanvullende controles volledig wilt onderdrukken, stelt u de omgevingsvariabele in op de speciale sentinel-waarde -1, zoals hieronder wordt weergegeven.
-
⚠️ Waarschuwing: stel de waarde van de omgevingsvariabele alleen in op -1 als u zeker weet dat de doeltoepassing geen niet-vertrouwde certificaatinvoer verwerkt.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1
Optie 4: de aanvullende validatie wijzigen of onderdrukken met Behulp van AppContext
Toepasselijkheid: deze optie is alleen van toepassing op .NET 6.0+. Deze is niet van toepassing op .NET Framework
Hoewel .NET standaard importbewerkingen beperkt tot maximaal 600.000 iteraties van een wachtwoord, kan deze limiet voor de hele toepassing worden geconfigureerd met behulp van de switch AppContext. Deze nieuwe limiet is van toepassing op alle aanroepen van de betrokken API's die hierboven worden vermeld.
Als u de limiet wilt wijzigen, stelt u de AppContext-switch System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit in op de waarde van wat de nieuwe limiet moet zijn. Als u bijvoorbeeld de limiet wilt instellen op 1.000.000 (één miljoen) iteraties, stelt u de schakeloptie in zoals hieronder wordt weergegeven.
-
Dit getal bepaalt de totale iteratielimiet. Dit is de som van het aantal MAC-iteraties, de versleutelde veilige inhoud en het iteratieaantal van de gehulde zak. Als u handmatig een PFX hebt geëxporteerd met behulp van een expliciet aantal iteraties <iter_count> (bijvoorbeeld via openssl pkcs12 -export -iter <iter_count>) en die PFX-blob wilt importeren, stelt u deze omgevingsvariabele in op een waarde die minstens zo groot is als de som van alle verwachte iteraties. In de praktijk kan .NET toestaan dat het totale aantal iteraties een beetje de expliciete limiet overschrijdt die hier is geconfigureerd.
De switch instellen in het projectbestand van uw toepassing (.csproj of .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>
U kunt ook een bestand met de naam runtimeconfig.template.json met de volgende inhoud in dezelfde map plaatsen die het projectbestand van uw toepassing bevat:
{
"configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000
}
}
Zie de documentatiepagina .NET Runtime-configuratie-instellingen voor meer informatie over het wijzigen van configuratie-instellingen voor .NET Runtime.
Als u de aanvullende controles volledig wilt onderdrukken, stelt u de configuratieswitch de speciale sentinel-waarde -1 in, zoals hieronder wordt weergegeven.
⚠️ Waarschuwing: stel de schakeloptie AppContext alleen in op -1 als u zeker weet dat de doeltoepassing geen niet-vertrouwde certificaatinvoer verwerkt.
In het projectbestand van de toepassing (.csproj of .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>
Of in het bestand runtimeconfig.template.json:
{
- "configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1
}
}
Optie 5: de aanvullende validatiemachine wijzigen of onderdrukken via het register (alleen Windows voor .NET Framework)
Toepasselijkheid: deze optie is alleen van toepassing op alle versies van .NET Framework. Dit is niet van toepassing op .NET 6.0+.
Hoewel .NET Framework standaard importbewerkingen beperken tot maximaal 600.000 iteraties van een wachtwoord, kan deze limiet voor de hele machine worden geconfigureerd met behulp van het HKLM-register. Deze nieuwe limiet is van toepassing op alle aanroepen van de betrokken API's die hierboven worden vermeld.
Als u de limiet wilt wijzigen, stelt u onder de registersleutelHKLM\Software\Microsoft\.NETFrameworkde waardePkcs12UnspecifiedPasswordIterationLimitin op de nieuwe limiet. Als u bijvoorbeeld de limiet wilt instellen op 1.000.000 (één miljoen) iteraties, voert u de opdrachten uit zoals hieronder wordt weergegeven vanaf een opdrachtprompt met verhoogde bevoegdheid.
-
Dit getal bepaalt de totale iteratielimiet. Dit is de som van het aantal MAC-iteraties, de versleutelde veilige inhoud en het iteratieaantal van de gehulde zak. Als u een PFX handmatig hebt geëxporteerd met behulp van een expliciet aantal iteraties <iter_count> (bijvoorbeeld via openssl pkcs12 -export -iter <iter_count>) en die PFX-blob wilt importeren, stelt u deze registerwaarde in op een waarde die minstens zo groot is als de som van alle verwachte iteraties. In de praktijk kan .NET Framework toestaan dat het totale aantal iteraties een beetje de expliciete limiet overschrijdt die hier is geconfigureerd.
-
De registerinstelling is afhankelijk van de architectuur. Om ervoor te zorgen dat toepassingen uw geconfigureerde waarde observeren, ongeacht hun doelarchitectuur, moet u zowel de 32-bits als de 64-bits registers wijzigen, zoals hieronder wordt weergegeven.
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
Als u de aanvullende controles volledig wilt onderdrukken, stelt u de registerwaarde in op -1 vanaf een opdrachtprompt met verhoogde bevoegdheid, zoals hieronder wordt weergegeven.
-
⚠️ Waarschuwing: stel de registerwaarde alleen in op -1 als u zeker weet dat de services die op de doelcomputer worden uitgevoerd, geen niet-vertrouwde certificaatinvoer verwerken.
-
Als u de sentinel -1 wilt instellen, gebruikt u het type REG_SZ in plaats van het type REG_DWORD. De registerinstelling is afhankelijk van de architectuur. Om ervoor te zorgen dat toepassingen uw geconfigureerde waarde observeren, ongeacht hun doelarchitectuur, moet u zowel de 32-bits als de 64-bits registers wijzigen, zoals hieronder wordt weergegeven.
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
Als u de registerwijzigingen wilt herstellen, verwijdert u de reg-waarde Pkcs12UnspecifiedPasswordIterationLimit van een opdrachtprompt met verhoogde bevoegdheid.
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32 reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64
Windows-specifieke notities
In Windows .NET Framework certificaten importeren via de functie PFXImportCertStore. Deze functie voert een eigen validatie uit, inclusief het plaatsen van eigen limieten voor het maximaal toegestane aantal iteraties van een PFX-blob. Deze controles vinden nog steeds plaats bij het importeren van PFX. De. NET-specifieke omgevingsvariabelen en registersleutels die hierboven worden beschreven, hebben geen invloed op hoe PFXImportCertStore deze controles uitvoert.