共用方式為


Windows 私密金鑰存留期已簡化

當工作負載在 Windows 上載入 PKCS#12/PFX 時,如果沒有設定 PersistKeySetEphemeralKeySet 儲存選項時,.NET 將決定何時不再需要私鑰並應該將其清除。 在舊版的 .NET (以及 .NET Framework) 中,使用了兩組不同的邏輯。 在 .NET 9 中,只使用一組邏輯。

先前的行為

在以前,當從 PKCS#12/PFX 載入憑證 (及其私鑰) 並使用 new X509Certificate2(pfx, password, flags) 時,載入的憑證代表私鑰的存留期。 當此憑證物件被處置時 (或在垃圾回收時未處置而最終被回收時),相關聯的私鑰也會被刪除。 共用擁有權或擁有權轉移不會發生。

當從 PKCS#12/PFX 載入憑證 (及其私鑰) 並使用 X509Certificate2Collection.Import(pfx, password, flags) 時,每個包含私鑰的載入憑證都會追踪其存留期,就像單一憑證載入一樣。 但是,除此之外,還會在憑證的原生複本上放置一個標記,以指示所有複本也應追蹤私鑰存留期。 如果基於相同的基礎 PCERT_CONTEXT 值建立第二個 X509Certificate2 物件,那麼無論哪個複本首先被處置 (或最終被回收),都會從另一個複本下方清除私鑰。

以下的程式碼失敗 (無論是使用 CryptographicException 還是 NullReferenceException),因為私鑰已刪除:

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

新的行為

從 .NET 9 開始,存留期一律與直接從 PKCS#12/PFX 載入產生的 X509Certificate2 執行個體相關聯。

先前行為一節中的相同代碼片段現在成功執行。

導入的版本

.NET 9 預覽 7

中斷性變更的類型

此變更為行為變更

變更原因

大部分載入 PKCS#12/PFX 的工作負載使用單一憑證載入方法,並理解與該方法相關聯的存留期機制。 集合載入的機制經常讓人感到意外,有時還會導致金鑰被過早清除。

如果你了解集合載入存留期管理,並依賴在複本上呼叫Dispose 來造成金鑰清除,請確保你也 (或改為) 在原始載入的物件上呼叫 Dispose

受影響的 API