Opmerking: Herzien op 22 juni 2023 om de oplossing en tijdelijke oplossingen bij te werken
Opmerking: Herzien op 15 juni 2023 om tijdelijke omzeilingsopties 4 en 5 bij te werken
Achtergrond
Op 13 juni 2023 heeft Microsoft een beveiligingsupdate voor .NET Framework en .NET uitgebracht die van invloed is op de manier waarop 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 zou zijn geslaagd vóór de update.
In dit document worden de wijzigingen en tijdelijke oplossingen beschreven die beschikbaar zijn voor de desbetreffende toepassingen.
Software waarin dit probleem optreedt
- .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
- new X509Certificate(byte[])
- X509Certificate.Import (byte[])
- new X509Certificate2(byte[])
- X509Certificate2.Import (byte[])
- X509Certificate2Collection.Import(byte[])
Beschrijving van wijziging
Vóór de wijziging van 13 juni 2023, wanneer .NET Framework en .NET worden gepresenteerd met een binaire certificaatblob voor import, delegeerden .NET Framework en .NET doorgaans de validatie en het importeren van de blob naar het onderliggende besturingssysteem. In Windows bijvoorbeeld vertrouwen .NET Framework en .NET doorgaans op de PFXImportCertStore-API voor validatie en import.
Vanaf de wijziging van 13 juni 2023, wanneer .NET Framework en .NET worden gepresenteerd met een binaire certificaatblob voor import, zullen .NET Framework en .NET in sommige gevallen aanvullende validatie uitvoeren voordat de blob aan het onderliggende besturingssysteem wordt overhandigd. Met deze aanvullende validatie wordt een reeks heuristische controles uitgevoerd om te bepalen of het binnenkomende certificaat kwaadwillig bronnen zou uitputten bij het importeren. Omdat dit extra validatie is die verder gaat dan wat het onderliggende besturingssysteem normaal zou uitvoeren, kunnen certificaatblobs worden geblokkeerd die vóór de wijziging van 13 juni 2023 met succes zouden zijn geïmporteerd.
Bekende regressies
Als een X.509-certificaat is geëxporteerd als een PFX-blob met een ongebruikelijk hoog aantal wachtwoorditeratie, kan dat certificaat nu niet worden geïmporteerd. De meeste certificaatexportfaciliteiten gebruiken een iteratieaantal tussen de 2.000 en 10.000. Nadat de beveiligingsupdate is toegepast, mislukt het importeren voor certificaten met een iteratieaantal van meer dan 600.000.
Als een X.509-certificaat is geëxporteerd met een null-wachtwoord [bijvoorbeeld via
X509Certificate.Export(X509ContentType.Pfx, (string)null)of zonder wachtwoordX509Certificate.Export(X509ContentType.Pfx)]], kan dat certificaat nu niet meer worden geïmporteerd.
Opmerking
De bovenstaande regressie is behandeld in de update van 22 juni 2023 die in KB5028608 is besproken.
Als een X.509-certificaat is geëxporteerd als een PFX-blob met behulp van de mogelijkheid van Windows om de persoonlijke sleutel naar een SID te beveiligen, 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 Certificaatexport van Windows en in de wizard opgeven dat de persoonlijke sleutel moet worden beveiligd voor een domeingebruiker; ofwel
- Via de cmdlet Export-PfxCertificate van PowerShell met een expliciet
-ProtectToargument; of - Via het certutil-hulpprogramma waarin een expliciet
-protecttoargument wordt gegeven; of - Via de PFXExportCertStoreEx-API waar de PKCS12_PROTECT_TO_DOMAIN_SIDS markering wordt verstrekt.
Oplossingen & tijdelijke oplossingen
Er zijn verschillende tijdelijke oplossingen beschikbaar, afhankelijk van of u gerichte wijzigingen wilt aanbrengen op afzonderlijke oproepsites in uw code, het gedrag van één toepassing wilt wijzigen of wijzigingen voor de hele computer wilt aanbrengen.
Optie 1 (voorkeur): een bijgewerkte patch installeren
Opmerking
Dit is de voorkeursoptie, omdat hiermee vaak gerapporteerde 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 in KB5028608 is besproken.
Microsoft raadt klanten die regressies ervaren die zijn geïntroduceerd door de release van 13 juni 2023 aan om deze bijgewerkte patch te installeren voordat ze de tijdelijke oplossingen proberen die verderop in dit document worden vermeld.
Optie 2: de oproepsite 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 geleverd via een netwerkaanvraag van een niet-geverifieerde of niet-geautoriseerde client?
Microsoft raadt u ten zeerste aan geen PFX-blobs te importeren die u door niet-geverifieerde of onbevoegde clients zijn verstrekt, omdat deze blobs kwaadaardig bronuitputtingsgedrag kunnen bevatten.
Als u een blob met een openbare sleutel moet importeren die u van een niet-vertrouwde partij hebt ontvangen, kunt u de volgende code gebruiken om een dergelijke blob veilig te importeren. In deze voorbeeldcode wordt de methode GetCertContentType gebruikt om te bepalen wat het onderliggende type van de certificaat-blob is, en worden PFX-blobs geweigerd in gevallen waarin u alleen verwacht een openbare certificaat-blob te importeren. De X509Certificate2(byte[]) constructor is veilig voor gebruik wanneer u niet-vertrouwde niet-PFX-blobs krijgt.
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 wachtwoordloze certificaatblob voor persoonlijke sleutels moet importeren en u hebt vastgesteld dat de blob betrouwbaar is, kunt u de aanvullende validatiecontroles die zijn uitgevoerd door de beveiligingsrelease van 13 juni 2023 onderdrukken door een andere constructoroverbelasting 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 met behulp van een omgevingsvariabele wijzigen of onderdrukken
Toepasselijkheid: deze optie is alleen van toepassing op alle versies van .NET Framework. Deze geldt niet voor .NET 6.0+.
Hoewel in .NET Framework importbewerkingen standaard worden beperkt tot niet meer dan 600.000 iteraties van een wachtwoord, kan deze limiet worden geconfigureerd voor een app- of computerbrede basis door een omgevingsvariabele te gebruiken. Deze nieuwe limiet is van toepassing op alle aanroepen van de hierboven vermelde Betrokken API's.
Als u de limiet wilt wijzigen, stelt u de omgevingsvariabele COMPlus_Pkcs12UnspecifiedPasswordIterationLimit in op de waarde van de nieuwe limiet. Als u de limiet bijvoorbeeld 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, versleutelde veilige inhoud en het aantal iteraties van de shrouded bag. Als u handmatig een PFX hebt geëxporteerd met behulp van een expliciete iteratietelling <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 ten minste net zo groot is als de som van alle verwachte iteraties. In de praktijk kan het in .NET Framework en .NET zijn toegestaan dat het totale aantal iteraties de expliciete limiet die hier is geconfigureerd iets overschrijdt.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000
Als u de extra controles helemaal wilt uitschakelen, stelt u de omgevingsvariabele in op de speciale sentinel-waarde -1, zoals hieronder wordt weergegeven.
- ⚠️ Waarschuwing: Stel de omgevingsvariabele waarde alleen in op -1 als u zeker weet dat de doeltoepassing niet-vertrouwde certificaatinvoer niet verwerkt.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1
Optie 4: de aanvullende validatie met AppContext aanpassen of onderdrukken
Toepasselijkheid: Deze optie is alleen van toepassing op .NET 6.0+. Deze is niet van toepassing op .NET Framework
Hoewel voor .NET importbewerkingen standaard niet meer dan 600.000 iteraties van een wachtwoord nodig zijn, kan deze limiet voor de hele toepassing worden geconfigureerd met behulp van de AppContext-schakeloptie. Deze nieuwe limiet is van toepassing op alle aanroepen van de hierboven vermelde Betrokken API's.
Als u de limiet wilt wijzigen, stelt u de AppContext-schakeloptie System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit in op de waarde van wat de nieuwe limiet moet zijn. Als u de limiet bijvoorbeeld wilt instellen op 1.000.000 (een miljoen) iteraties, schakelt u als volgt uit.
- Dit getal bepaalt de totale iteratielimiet. Dit is de som van het aantal MAC-iteraties, versleutelde veilige inhoud en het aantal iteraties van de shrouded bag. Als u handmatig een PFX hebt geëxporteerd met behulp van een expliciete iteratietelling <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 ten minste net zo groot is als de som van alle verwachte iteraties. In de praktijk kan .NET toestaan dat het totale aantal iteraties elke expliciete limiet die hier is geconfigureerd iets overschrijdt.
De schakeloptie instellen in het projectbestand van uw toepassing (.csproj of .vbproj):
<!--
- Deze schakeloptie werkt alleen als het huidige projectbestand een toepassing vertegenwoordigt. Het heeft geen effect als het huidige projectbestand een gedeelde bibliotheek vertegenwoordigt.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption Include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="1000000" />
</ItemGroup>
U kunt ook een bestand met de naam runtimeconfig.template.json en de volgende inhoud opslaan in dezelfde map die het projectbestand van uw toepassing bevat:
{
"configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000
}
}
Zie de documentatiepagina voor . NET Runtime-configuratie-instellingen voor meer informatie over het wijzigen van de configuratie-instellingen voor .NET runtime.
Als u de aanvullende controles helemaal wilt uitsluiten, stelt u de configuratieschakelaar in op de speciale sentinel-waarde -1, zoals hieronder wordt weergegeven.
⚠️ Waarschuwing: Zet de AppContext-schakelaar alleen op -1 als u zeker weet dat de doeltoepassing niet-vertrouwde certificaatinvoer niet verwerkt.
In het projectbestand van de toepassing (.csproj of .vbproj):
<!--
- Deze schakeloptie werkt alleen als het huidige projectbestand een toepassing vertegenwoordigt. Het heeft geen effect als het huidige projectbestand een gedeelde bibliotheek vertegenwoordigt.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="-1" />
</ItemGroup>
Of in het runtimeconfig.template.json bestand:
{
- "configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1
}
}
Optie 5: de extra validatie machinebreed wijzigen of onderdrukken via het register (alleen Windows-only voor .NET Framework)
Toepasselijkheid: deze optie is alleen van toepassing op alle versies van .NET Framework. Deze geldt niet voor .NET 6.0+.
Hoewel in .NET Framework importbewerkingen standaard beperkt tot niet meer dan 600.000 iteraties van een wachtwoord, kan deze limiet voor de gehele computer worden geconfigureerd met behulp van het HKLM-register. Deze nieuwe limiet is van toepassing op alle aanroepen van de hierboven vermelde Betrokken API's.
Als u de limiet wilt wijzigen, stelt u onder de registersleutel HKLM\Software\Microsoft\.NETFrameworkde waarde Pkcs12UnspecifiedPasswordIterationLimit in op de waarden die de nieuwe limiet moet zijn. Als u de limiet bijvoorbeeld wilt instellen op 1.000.000 (een miljoen) iteraties, voert u de hieronder weergegeven opdrachten uit vanaf een opdrachtprompt met verhoogde bevoegdheid.
- Dit getal bepaalt de totale iteratielimiet. Dit is de som van het aantal MAC-iteraties, versleutelde veilige inhoud en het aantal iteraties van de shrouded bag. Als u handmatig een PFX hebt geëxporteerd met behulp van een expliciete iteratietelling <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 ten minste gelijk is aan de som van alle verwachte iteraties. In de praktijk kan het in .NET Framework mogelijk zijn dat het totale aantal iteraties de expliciete limiet die hier is geconfigureerd iets overschrijdt.
- De registerinstelling is afhankelijk van de architectuur. Als u er zeker van wilt zijn dat toepassingen de geconfigureerde waarde naleven, ongeacht hun doelarchitectuur, moet u niet vergeten om zowel de 32-bits als de 64-bits registers te 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 extra controles helemaal wilt uitschakelen, 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 schildwacht -1 wilt instellen, gebruikt u het type REG_SZ in plaats van het type REG_DWORD. De registerinstelling is afhankelijk van de architectuur. Als u er zeker van wilt zijn dat toepassingen de geconfigureerde waarde naleven, ongeacht hun doelarchitectuur, moet u niet vergeten om zowel de 32-bits als de 64-bits registers te 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 ongedaan wilt maken, verwijdert u de registerwaarde Pkcs12UnspecifiedPasswordIterationLimit uit 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 opmerkingen
In Windows importeert .NET Framework certificaten via de functie PFXImportCertStore. Deze functie voert zijn eigen validatie uit, inclusief het plaatsen van eigen limieten voor het maximaal toelaatbare 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 de manier waarop PFXImportCertStore deze controles uitvoert.