Freigeben über


Lebensdauer von Windows Private Key vereinfacht

Wenn eine Workload eine PKCS#12/PFX unter Windows lädt, ohne entweder die Speicheroption PersistKeySet oder EphemeralKeySet festzulegen, bestimmt .NET, wann der private Schlüssel nicht mehr benötigt wird und wann er gelöscht werden soll. In früheren Versionen von .NET (und in .NET Framework) wurden zwei verschiedene Logiksätze verwendet. In .NET 9 gibt es einen einzigen Logiksatz.

Vorheriges Verhalten

Wenn zuvor ein Zertifikat (und sein privater Schlüssels) aus einer PKCS#12/PFX mit new X509Certificate2(pfx, password, flags) geladen wurde, wies das geladene Zertifikat die Lebensdauer des privaten Schlüssels auf. Wurde dieses Zertifikatobjekt freigegeben (oder abgeschlossen, wenn hierfür die Garbage Collection durchgeführt wurde, ohne freigegeben zu werden), wurde der zugeordnete private Schlüssel gelöscht. Es gab weder ein gemeinsames Eigentum noch eine Übertragung des Eigentums.

Wenn ein Zertifikat (und sein privater Schlüssel) aus einer PKCS#12/PFX mit X509Certificate2Collection.Import(pfx, password, flags) geladen wurde, verfolgte jedes geladene Zertifikat, das über einen privaten Schlüssel verfügte, dieselbe Lebensdauer nach, wie beim Laden des einzelnen Zertifikats. Darüber hinaus wurde die native Kopie des Zertifikats mit einer Anmerkung versehen, die angab, dass alle Kopien die Lebensdauer des privaten Schlüssels nachverfolgen sollten. Wurde ein zweites X509Certificate2-Objekt auf Basis desselben PCERT_CONTEXT-Werts erstellt, so löschte die freigegebene (oder abgeschlossene) Kopie zuerst den privaten Schlüssel aus der anderen Kopie.

Der folgende Code ist fehlgeschlagen (entweder mit einer CryptographicException oder einer NullReferenceException), da der private Schlüssel gelöscht wurde:

X509Certificate2Collection coll = new X509Certificate2Collection(pfx, password, X509KeyStorageFlags.DefaultKeySet);
X509Certificate2Collection coll2 = coll.Find(X509FindType.FindBySubjectName, "", false);

coll2 = null;
GC.Collect();
GC.WaitForPendingFinalizers();

using (RSA key = coll[0].GetRSAPrivateKey())
{
    key.SignData(pfx, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}

Neues Verhalten

Ab .NET 9 wird die Lebensdauer immer der X509Certificate2-Instanz zugeordnet, die direkt aus der PKCS#12/PFX erstellt wurde.

Derselbe Codeausschnitt im Abschnitt Vorheriges Verhalten ist jetzt erfolgreich.

Eingeführt in Version

.NET 9 Preview 7

Typ des Breaking Changes

Diese Änderung ist eine Verhaltensänderung.

Grund für die Änderung

Die meisten Arbeitslasten, die eine PKCS#12/PFX laden, verwenden die Methode des Ladens eines einzelnen Zertifikats und verstehen die Lebensdauermechanik, die dieser Methode zugeordnet ist. Die der Sammelladung zugeordnete Mechanik sorgte oft für überraschende Ergebnisse und führte manchmal zu einer vorzeitigen Löschung des Schlüssels.

Wenn Sie die Verwaltung der Lebensdauer des Sammelladung verstanden haben und Dispose auf einem Klon aufrufen mussten, um das Löschen des Schlüssels auszulösen, stellen Sie sicher, dass Sie auch (oder stattdessen) Dispose auf dem ursprünglich geladenen Objekt aufrufen.

Betroffene APIs