Notera: Reviderad 22 juni 2023 för att uppdatera lösning och lösningar
Notera: Reviderad 15 juni 2023 för att uppdatera lösningen alternativ 4 och 5
Bakgrund
Den 13 juni 2023 släppte Microsoft en säkerhetsuppdatering till .NET Framework och .NET som påverkar hur körningen importerar X.509-certifikat. De här ändringarna kan göra att X.509-certifikatimport genererar CryptographicException i scenarier där importen skulle ha lyckats före uppdateringen.
Det här dokumentet beskriver ändringen och tillgängliga lösningar för program som påverkas.
Programvara som berörs
- .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
Berörda API:er
- new X509Certificate(byte[])
- X509Certificate.Import(byte[])
- new X509Certificate2(byte[])
- X509Certificate2.Import(byte[])
- X509Certificate2Collection.Import(byte[])
Beskrivning av ändring
Före ändringen den 13 juni 2023, när .NET Framework och .NET presenteras med en binär certifikatblob för import, delegerar .NET Framework och .NET vanligtvis validering och import av bloben till det underliggande operativsystemet. I Windows förlitar sig till exempel .NET Framework och .NET vanligtvis på PFXImportCertStore-API:et för verifiering och import.
Från och med ändringen den 13 juni 2023, när .NET Framework och .NET presenteras med en binär certifikatblob för import, utför .NET Framework och .NET i vissa fall ytterligare validering innan bloben överlämnas till det underliggande operativsystemet. Den här ytterligare verifieringen utför en serie heuristiska kontroller för att avgöra om det inkommande certifikatet skadligt skulle förbruka resurser vid import. Eftersom detta är ytterligare validering utöver vad det underliggande operativsystemet normalt skulle utföra kan det blockera certifikatblobar som skulle ha importerats före ändringen den 13 juni 2023.
Kända regressioner
Om ett X.509-certifikat har exporterats som en PFX-blob med ett ovanligt högt antal lösenordsiterationer kanske certifikatet nu inte kan importeras. De flesta certifikatexportanläggningar använder ett iterationsantal någonstans mellan 2 000 och 10 000. När säkerhetsuppdateringen har installerats misslyckas importen av certifikat som innehåller ett iterationsantal som är större än 600 000.
Om ett X.509-certifikat har exporterats med ett null-lösenord [t.ex. via
X509Certificate.Export(X509ContentType.Pfx, (string)null)eller den lösenordsfriaX509Certificate.Export(X509ContentType.Pfx)], kanske certifikatet nu inte kan importeras.
Obs
Ovanstående regression har åtgärdats i uppdateringen från den 22 juni 2023 som diskuterades i KB5028608.
Om ett X.509-certifikat har exporterats som en PFX-blob med hjälp av Windows funktion för att skydda den privata nyckeln till ett SID kanske certifikatet nu inte kan importeras. Detta påverkar PFX-blobar som skapats på följande sätt:
- Via Windows guide för certifikatexport och ange i guiden att den privata nyckeln ska skyddas för en domänanvändare; eller
- Via PowerShell-cmdleten Export-PfxCertificate där ett explicit
-ProtectToargument anges, eller - Via certutil-verktyget där ett explicit
-protecttoargument anges, eller - Via PFXExportCertStoreEx-API :et där PKCS12_PROTECT_TO_DOMAIN_SIDS flagga tillhandahålls.
Lösning & lösningar
Det finns olika lösningar, beroende på om du vill göra riktade ändringar på enskilda anropsplatser i koden, ändra beteendet för ett enskilt program eller göra ändringar för hela datorn.
Alternativ 1 (rekommenderas) – Installera en uppdaterad korrigering
Obs
Det här är det rekommenderade alternativet eftersom det hanterar vanliga rapporterade kundregressioner och inte kräver några kodändringar i programmet.
Tillämplighet: Det här alternativet gäller alla versioner av .NET Framework och .NET.
Det här problemet har åtgärdats i uppdateringen från 22 juni 2023 som diskuterades i KB5028608.
Microsoft rekommenderar att kunder som upplever regressioner som introducerades av versionen från 13 juni 2023 provar att installera den här uppdaterade korrigeringen innan du provar de lösningar som anges senare i det här dokumentet.
Alternativ 2 - Ändra samtalswebbplatsen
Tillämplighet: Det här alternativet gäller alla versioner av .NET Framework och .NET.
Överväg om bloben som du importerar är betrodd. Hämtades bloben till exempel från en betrodd plats, till exempel en databas eller konfigurationsfil under din kontroll, eller tillhandahölls den via en nätverksbegäran som gjordes av en icke-autentiserad eller oprivilegierad klient?
Microsoft rekommenderar starkt att du inte importerar PFX-blobar som tillhandahålls av oautentiserade eller oprivilegierade klienter, eftersom dessa blobar kan innehålla skadliga resursöverbelastningsbeteenden.
Om du behöver importera en certifikatblob för offentlig nyckel som du fått av en ej betrodd part kan du använda följande kod för att importera en sådan blob på ett säkert sätt. Den här exempelkoden använder GetCertContentType metoden för att avgöra vilken underliggande typ av certifikatblob som är och avvisar PFX-blobar i fall där du bara förväntar dig att importera en certifikatblob med offentlig nyckel. Konstruktorn X509Certificate2(byte[]) är säker att använda när den ges icke-betrodda icke-PFX-blobar.
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);
}
}
Om du behöver importera en lösenordsfri certifikatblob för privat nyckel och du har fastställt att bloben är tillförlitlig kan du ignorera de ytterligare valideringskontroller som utfördes av säkerhetsversionen från den 13 juni 2023 genom att anropa en annan konstruktoröverlagring. Du kan till exempel anropa konstruktoröverlagringen som accepterar ett stränglösenordsargument och skickar null för argumentvärdet.
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);
Alternativ 3 - Ändra eller ignorera den ytterligare verifieringen med hjälp av en miljövariabel
Tillämplighet: Det här alternativet gäller endast alla versioner av .NET Framework. Den gäller inte för .NET 6.0+.
Medan .NET Framework som standard begränsar importåtgärder till högst 600 000 iterationer av ett lösenord, kan den här gränsen konfigureras på app- eller datorövergripande basis med hjälp av en miljövariabel. Den här nya gränsen gäller för alla anrop av de berörda API:erna som anges ovan.
Om du vill ändra gränsen ställer du in miljövariabeln COMPlus_Pkcs12UnspecifiedPasswordIterationLimit till värdet för vad det nya gränsvärdet ska vara. Om du till exempel vill ange gränsen till 1 000 000 (en miljon) iterationer anger du miljövariabeln enligt nedan.
- Det här talet styr den totala iterationsgränsen, som är summan av antalet MAC-iterationer, krypterat säkert innehåll och antalet iterationer i den dolda påsen. Om du har exporterat en PFX manuellt med ett explicit antal iterationer <iter_count> (t.ex. via openssl pkcs12 -export -iter <iter_count>) och vill importera den PFX-bloben anger du den här miljövariabeln till ett värde som är minst lika stort som summan av alla förväntade iterationer. I praktiken kan .NET Framework och .NET tillåta att det totala antalet iterationer överstiger någon explicit gräns som konfigureras här.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000
Om du vill ignorera de ytterligare kontrollerna helt anger du miljövariabeln till det särskilda sentinelvärdet -1, enligt nedan.
- ⚠️ Varning: Ställ bara in miljövariabelns värde till -1 om du är säker på att målprogrammet inte hanterar icke-betrodda certifikatindata.
COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1
Alternativ 4 – Ändra eller ignorera den ytterligare verifieringen med AppContext
Tillämplighet: Det här alternativet gäller endast för .NET 6.0+. Den gäller inte för .NET Framework
Medan .NET som standard begränsar importåtgärder till att inte ta mer än 600 000 iterationer av ett lösenord, kan den här gränsen konfigureras för hela programmet med hjälp av AppContext-växeln. Den här nya gränsen gäller för alla anrop av de berörda API:erna som anges ovan.
Om du vill ändra gränsen anger du AppContext-växeln System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit till värdet för vad den nya gränsen ska vara. Om du till exempel vill ange gränsen till 1 000 000 (en miljon) iterationer ställer du in växeln enligt nedan.
- Det här talet styr den totala iterationsgränsen, som är summan av antalet MAC-iterationer, krypterat säkert innehåll och antalet iterationer i den dolda påsen. Om du har exporterat en PFX manuellt med ett explicit antal iterationer <iter_count> (t.ex. via openssl pkcs12 -export -iter <iter_count>) och vill importera den PFX-bloben anger du den här miljövariabeln till ett värde som är minst lika stort som summan av alla förväntade iterationer. I praktiken kan .NET tillåta att det totala antalet iterationer något överskrider någon explicit gräns som konfigureras här.
Så här ställer du in växeln i programmets projektfil (.csproj eller .vbproj):
<!--
- Den här växeln fungerar bara om den aktuella projektfilen representerar ett program. Det har ingen effekt om den aktuella projektfilen representerar ett delat bibliotek.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" Value="1000000" />
</ItemGroup>
Alternativt kan du placera en fil med namnet runtimeconfig.template.json och följande innehåll i samma katalog som innehåller programmets projektfil:
{
"configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": 1000000
}
}
Mer information om hur du ändrar konfigurationsinställningarna för .NET Runtime finns på dokumentationssidan Konfigurationsinställningar för .NET Runtime.
Om du vill ignorera de ytterligare kontrollerna helt anger du konfigurationsväxeln det särskilda sentinelvärdet -1, enligt nedan.
⚠️ Varning: Ställ bara in AppContext-växeln på -1 om du är säker på att målprogrammet inte hanterar icke-betrodda certifikatindata.
I programmets projektfil (.csproj eller .vbproj):
<!--
- Den här växeln fungerar bara om den aktuella projektfilen representerar ett program. Det har ingen effekt om den aktuella projektfilen representerar ett delat bibliotek.
-->
<ItemGroup>
- <RuntimeHostConfigurationOption include="System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit" value="-1" />
</ItemGroup>
Eller i den runtimeconfig.template.json filen:
{
- "configProperties": {
- "System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit": -1
}
}
Alternativ 5 - Ändra eller inaktivera ytterligare validering i hela datorn via registret (endast Windows för .NET Framework)
Tillämplighet: Det här alternativet gäller endast alla versioner av .NET Framework. Den gäller inte för .NET 6.0+.
Medan .NET Framework som standard begränsar importåtgärder till högst 600 000 iterationer av ett lösenord, kan den här gränsen konfigureras för hela datorn med hjälp av HKLM-registret. Den här nya gränsen gäller för alla anrop av de berörda API:erna som anges ovan.
Om du vill ändra gränsen anger du värdet Pkcs12UnspecifiedPasswordIterationLimit till den nya gränsen under registernyckelnHKLM\Software\Microsoft\.NETFramework. Om du till exempel vill ange gränsen till 1 000 000 (en miljon) iterationer kör du kommandona enligt nedan från en upphöjd kommandotolk.
- Det här talet styr den totala iterationsgränsen, som är summan av antalet MAC-iterationer, krypterat säkert innehåll och antalet iterationer i den dolda påsen. Om du har exporterat en PFX manuellt med ett explicit antal iterationer <iter_count> (t.ex. via openssl pkcs12 -export -iter <iter_count>) och vill importera den PFX-bloben anger du registervärdet till ett värde som är minst lika stort som summan av alla förväntade iterationer. I praktiken kan .NET Framework tillåta att det totala antalet iterationer överstiger någon explicit gräns som konfigureras här.
- Registerinställningen är arkitekturberoende. För att säkerställa att programmen observerar det konfigurerade värdet oavsett målarkitektur ska du komma ihåg att ändra både 32-bitars- och 64-bitarsregistren enligt nedan.
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
Om du vill ignorera de ytterligare kontrollerna helt anger du registervärdet till -1 från en upphöjd kommandotolk, enligt nedan.
- ⚠️ Varning: Ange endast registervärdet till -1 om du är säker på att tjänsterna som körs på måldatorn inte hanterar indata för ej betrodda certifikat.
- Om du vill ange -1 sentinel använder du REG_SZ typen i stället för REG_DWORD typen. Registerinställningen är arkitekturberoende. För att säkerställa att programmen observerar det konfigurerade värdet oavsett målarkitektur ska du komma ihåg att ändra både 32-bitars- och 64-bitarsregistren enligt nedan.
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
Om du vill återställa registerändringarna tar du bort registreringsvärdet Pkcs12UnspecifiedPasswordIterationLimit från en upphöjd kommandotolk.
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:32
reg delete "HKLM\Software\Microsoft\.NETFramework" /v Pkcs12UnspecifiedPasswordIterationLimit /reg:64
Windows-specifika anteckningar
I Windows importerar .NET Framework certifikat via funktionen PFXImportCertStore. Den här funktionen utför egen validering, inklusive att placera egna gränser för en PFX-blobs högsta tillåtna antal iterationer. Dessa kontroller kommer fortfarande att ske vid PFX-import. Metoden . NET-specifika miljövariabler och registernycklar som beskrivs ovan påverkar inte hur PFXImportCertStore utför dessa kontroller.