KB5025823 Promena načina na koji .NET aplikacije uvoze X.509 certifikate

Primenjuje se na
.NET

Napomena: Revidirano 22. jun 2023. radi ažuriranja rezolucije i privremenih rešenja

Napomena: Revidirano 15. jun 2023. radi ažuriranja rešenja oko opcija 4 i 5

Pozadina

Microsoft je 13. juna 2023. objavio bezbednosnu ispravku za .NET Framework i .NET koja utiče na način na koji runtime uvozi X.509 sertifikate. Ove promene mogu da dovedu do toga da uvoz X.509 certifikata baci CryptographicException u scenarijima u kojima bi uvoz uspeo pre ažuriranja.

Ovaj dokument opisuje promene i privremena rešenja dostupna za aplikacije na koje ovo utiče.

Ugroženi softver

  • .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

API-ji na koje ovo utiče

Opis promene

Pre promene 13. juna 2023. godine, kada se za .NET Framework i .NET predstave blob binarni certifikat za uvoz, .NET Framework i .NET obično delegiraju proveru valjanosti i uvoz blob objekta osnovnom operativnom sistemu. Na primer, u operativnom sistemu Windows, .NET Framework i .NET se obično oslanjaju na PFXImportCertStore API za proveru valjanosti i uvoz.

Od promene 13. juna 2023. godine, kada se za .NET Framework i .NET predstavi blob binarni certifikat za uvoz, .NET Framework i .NET će u nekim okolnostima izvršiti dodatnu proveru valjanosti pre nego što preda blob osnovnom operativnom sistemu. Ova dodatna validacija vrši niz heurističkih provera u cilju utvrđivanja da li bi dolazni certifikat zlonamerno iscrpio resurse prilikom uvoza. Pošto je ovo dodatna provera valjanosti koja prevazilazi ono što bi osnovni operativni sistem obično obavljao, on može da blokira blob objekte certifikata koji bi uspešno uvezeni pre promene 13. juna 2023.

Poznate regresije

  1. Ako je X.509 certifikat izvezen kao PFX blob pomoću izuzetno velikog broja iteracija lozinke, taj certifikat možda sada ne uspe da se uveze. Većina objekata za izvoz certifikata koristi broj iteracija negde između 2.000 i 10.000. Nakon primene bezbednosne ispravke, uvoz neće uspeti za certifikate koji sadrže broj iteracija veći od 600.000.

  2. Ako je X.509 certifikat izvezen pomoću nulte lozinke [npr. putem X509Certificate.Export(X509ContentType.Pfx, (string)null) lozinke ili bez X509Certificate.Export(X509ContentType.Pfx)]lozinke, taj certifikat možda sada ne uspe da se uveze.
     

    Napomena

    Gornja regresija je rešena u ispravci od 22. juna 2023. o kojoj se govori u KB5028608.

  3. Ako je X.509 certifikat izvezen kao PFX blob pomoću mogućnosti operativnog sistema Windows da zaštiti privatni ključ za SID podatke, taj certifikat možda sada ne uspe da se uveze. To će uticati na PFX blob objekte kreirane na sledeće načine:

    • putem Windows čarobnjaka za izvoz certifikata i navođenje u čarobnjaku da privatni ključ treba da bude zaštićen za korisnika domena; ili
    • putem PowerShell-ove cmdlet komande Export-PfxCertificate gde je obezbeđen eksplicitni -ProtectTo argument; ili
    • Preko uslužnog programa certutil gde je eksplicitan -protectto argument naveden; ili
    • Preko API-ja PFXExportCertStoreEx u kom je navedena zastavica za PKCS12_PROTECT_TO_DOMAIN_SIDS.

Rezolucija & privremena rešenja

Postoje razna privremena rešenja u zavisnosti od toga da li želite da napravite ciljane promene na pojedinačnim lokacijama poziva u okviru koda ili želite da promenite ponašanje jedne aplikacije ili da napravite promene na nivou računara.

Opcija 1 (poželjno) - Instaliranje ažurirane zakrpe

Napomena

Ovo je poželjna opcija jer se ona bavi regresijama klijenata koje se često prijavljuju i ne zahteva nikakve promene koda za aplikaciju.

Primenljivost: Ova opcija se odnosi na sve verzije .NET Framework i .NET.

Ovaj problem je rešen u ispravci od 22. juna 2023. o kojoj se govori u KB5028608.

Microsoft preporučuje da korisnici koji imaju regresije uvedene u izdanju od 13. juna 2023. pokušavaju da instaliraju ovu ažuriranu zakrpu pre nego što pokušaju zaobilaženje problema navedeno u nastavku ovog dokumenta.

Opcija 2 – Izmena lokacije poziva

Primenljivost: Ova opcija se odnosi na sve verzije .NET Framework i .NET.

Razmislite da li je blob koji uvozite pouzdan. Na primer, da li je blob preuzet sa pouzdane lokacije, kao što je baza podataka ili konfiguraciona datoteka pod vašom kontrolom, ili je obezbeđen putem mrežnog zahteva koji je uputio neovlašćeni ili neprivilegovani klijent?

Microsoft izričito preporučuje da ne uvozite PFX blob objekte koje su vam obezbedili neovlašćeni ili neprivilegovani klijenti jer ti blobovi mogu da sadrže zlonamerna ponašanja iscrpljivanja resursa.

Ako treba da uvezete blob certifikata javnog ključa koji vam je dala nepouzdana strana, možete da koristite sledeći kôd da biste bezbedno uvezli takav blob. Ovaj uzorak koda koristi metod GetCertContentType kako bi odredio koji je osnovni tip blob objekta certifikata i odbacuje PFX blob objekte u slučajevima kada očekujete da uvezete samo blob certifikata javnog ključa. Konstruktor X509Certificate2(byte[]) je bezbedan za korišćenje kada su dati nepouzdani blobovi koji nisu PFX.


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

Ako treba da uvezete blob certifikata privatnog ključa bez lozinke i utvrdili ste da je blob pouzdan, možete da sprečite dodatne provere provere valjanosti koje je izvršilo bezbednosno izdanje od 13. juna 2023. tako što ćete pozvati drugo preopterećenje konstruktora. Na primer, možete da pozovete konstruktor preopterećenja koji prihvata argument niske lozinke i prosledi vrednost "null" za vrednost argumenta.

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

3. opcija – Izmena ili sprečavanje dodatne validacije pomoću promenljive okruženja

Primenljivost: Ova opcija se odnosi samo na sve verzije .NET Framework.  Ne odnosi se na .NET 6.0+.

Iako .NET Framework podrazumevano ograničava operacije uvoza tako da ne uzimaju više od 600.000 iteracija lozinke, to ograničenje može da se konfiguriše na nivou aplikacije ili na celom računaru pomoću promenljive okruženja. Ovo novo ograničenje će se primeniti na sve pozive gorenavedenih API-ja na koje ovo utiče.

Da biste promenili ograničenje, podesite promenljivu COMPlus_Pkcs12UnspecifiedPasswordIterationLimit okruženja na vrednost novog ograničenja. Na primer, da biste granicu postavili na 1.000.000 (milion) iteracija, postavite promenljivu okruženja kao što je prikazano ispod.

  • Ovaj broj kontroliše ukupno ograničenje iteracije, koje predstavlja zbir broja MAC iteracija, šifrovanog bezbednog sadržaja i broja iteracija pokrivene torbe. Ako ste ručno izvezli PFX pomoću eksplicitnog broja <iteracija iter_count> (npr. putem openssl pkcs12 -export -iter <iter_count>) i želite da uvezete taj PFX blob, podesite ovu promenljivu okruženja na vrednost koja je najmanje velika kao zbir svih očekivanih iteracija. U praksi, .NET Framework i .NET mogu da dozvole da ukupan broj iteracija malo premaši bilo koje eksplicitno ograničenje konfigurisano ovde.

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=1000000

Da biste u potpunosti sprečili dodatne provere, podesite promenljivu okruženja na specijalnu vrednost Sentinel -1, kao što je prikazano ispod.

  • ️ Upozorenje: Vrednost promenljive okruženja postavite na -1 samo ako ste sigurni da ciljna aplikacija ne rukuje unosom nepouzdanog certifikata.

COMPlus_Pkcs12UnspecifiedPasswordIterationLimit=-1

4. opcija – Izmena ili sprečavanje dodatne provere valjanosti pomoću funkcije AppContext

Primjenjivost: Ova opcija se odnosi samo na .NET 6.0+.  Ne odnosi se na .NET Framework

Iako .NET podrazumevano ograničava operacije uvoza tako da ne uzimaju više od 600.000 iteracija lozinke, to ograničenje može da se konfiguriše u celoj aplikaciji pomoću prekidača AppContext. Ovo novo ograničenje će se primeniti na sve pozive gorenavedenih API-ja na koje ovo utiče.

Da biste promenili ograničenje, postavite prekidač AppContext System.Security.Cryptography.Pkcs12UnspecifiedPasswordIterationLimit na vrednost novog ograničenja. Na primer, da biste granicu postavili na 1.000.000 (milion) iteracija, postavite prekidač kao što je prikazano ispod.

  • Ovaj broj kontroliše ukupno ograničenje iteracije, koje predstavlja zbir broja MAC iteracija, šifrovanog bezbednog sadržaja i broja iteracija pokrivene torbe. Ako ste ručno izvezli PFX pomoću eksplicitnog broja <iteracija iter_count> (npr. putem openssl pkcs12 -export -iter <iter_count>) i želite da uvezete taj PFX blob, podesite ovu promenljivu okruženja na vrednost koja je najmanje velika kao zbir svih očekivanih iteracija. U praksi, .NET može da dozvoli da ukupan broj iteracija malo premaši bilo koje eksplicitno konfigurisano ograničenje konfigurisano ovde.

Da biste postavili prekidač unutar datoteke projekta aplikacije (.csproj ili .vbproj):

<!--

  • Ovaj prekidač funkcioniše samo ako trenutna datoteka projekta predstavlja aplikaciju. Nema efekta ako trenutna datoteka projekta predstavlja deljenu biblioteku.

-->

<ItemGroup>

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

</ItemGroup>

Druga mogućnost je da postavite datoteku pod imenom runtimeconfig.template.json sa sledećim sadržajem u isti direktorijum u kojem se nalazi datoteka projekta aplikacije:

{

     "configProperties": {

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

      }

}

Više informacija o promeni postavki konfiguracije .NET vremena izvršavanja potražite na stranici dokumentacije sa postavkama konfiguracije .NET Runtime protokola.

Da biste u potpunosti sprečili dodatne provere, postavite konfiguracioni prekidač na specijalnu vrednost Sentinel -1, kao što je prikazano ispod.

️ Upozorenje: prekidač AppContext postavite na -1 samo ako ste sigurni da ciljna aplikacija ne rukuje unosom nepouzdanog certifikata.

U okviru datoteke projekta aplikacije (.csproj ili .vbproj):

<!--

  • Ovaj prekidač funkcioniše samo ako trenutna datoteka projekta predstavlja aplikaciju. Nema efekta ako trenutna datoteka projekta predstavlja deljenu biblioteku.

-->

<ItemGroup>

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

</ItemGroup>

Ili u runtimeconfig.template.json datoteci:

{

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

     }

}

Opcija 5 – Izmena ili suzbijanje dodatne provere valjanosti širom mašine preko registratora (samo za .NET Framework)

Primenljivost: Ova opcija se odnosi samo na sve verzije .NET Framework.  Ne odnosi se na .NET 6.0+.

Iako .NET Framework podrazumevano ograničava operacije uvoza tako da ne uzimaju više od 600.000 iteracija lozinke, ovo ograničenje se može konfigurisati na celom računaru pomoću HKLM registratora. Ovo novo ograničenje će se primeniti na sve pozive gorenavedenih API-ja na koje ovo utiče.

Da biste promenili ograničenje, u okviru ključa HKLM\Software\Microsoft\.NETFrameworkregistratora postavite vrednost Pkcs12UnspecifiedPasswordIterationLimit na novo ograničenje. Na primer, da biste postavili ograničenje na 1.000.000 (milion) iteracija, pokrenite komande kao što je prikazano ispod sa komandne linije sa punim privilegijama.

  • Ovaj broj kontroliše ukupno ograničenje iteracije, koje predstavlja zbir broja MAC iteracija, šifrovanog bezbednog sadržaja i broja iteracija pokrivene torbe. Ako ste ručno izvezli PFX pomoću eksplicitnog broja <iteracija iter_count> (npr. putem openssl pkcs12 -export -iter <iter_count>) i želite da uvezete taj PFX blob, postavite vrednost ovog registratora na vrednost koja je najmanje onoliko velika kao zbir svih očekivanih iteracija. U praksi, .NET Framework može da dozvoli da ukupan broj iteracija malo premaši bilo koje eksplicitno ograničenje konfigurisano ovde.
  • Postavka registratora zavisi od arhitekture. Da biste se uverili da aplikacije prate konfigurisanu vrednost bez obzira na ciljnu arhitekturu, ne zaboravite da izmenite i 32-bitne i 64-bitne registratore, kao što je prikazano ispod.

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

Da biste u potpunosti sprečili dodatne provere, postavite vrednost registratora na -1 iz komandne linije sa punim privilegijama, kao što je prikazano ispod.

  • ⚠️ Upozorenje: Vrednost registratora postavite na -1 samo ako ste sigurni da usluge pokrenute na ciljnom računaru ne rukuju unosom nepouzdanog certifikata.
  • Da biste podesili -1 Sentinel, koristite tip REG_SZ umesto tipa REG_DWORD. Postavka registratora zavisi od arhitekture. Da biste se uverili da aplikacije prate konfigurisanu vrednost bez obzira na ciljnu arhitekturu, ne zaboravite da izmenite i 32-bitne i 64-bitne registratore, kao što je prikazano ispod.

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

Da biste poništili promene registratora, izbrišite reg vrednost Pkcs12UnspecifiedPasswordIterationLimit iz komandne linije sa punim privilegijama.

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

Napomene specifične za Windows

U operativnom sistemu Windows, .NET Framework uvozi certifikate putem funkcije PFXImportCertStore. Ova funkcija izvršava sopstvenu validaciju, uključujući postavljanje sopstvenih ograničenja na maksimalni dozvoljeni broj iteracija PFX blob-a. Ove provere će se i dalje obavljati nakon uvoza PFX-a. Dokument . Promenljive okruženja i ključevi registratora specifični za NET mreže opisani iznad ne utiču na to kako PFXImportCertStore izvršava ove provere.