From b7c6e5279e13624d906c4dce3c2b9b6b51e8675a Mon Sep 17 00:00:00 2001 From: Drew Scoggins Date: Fri, 10 Jul 2026 10:35:20 -0700 Subject: [PATCH] Load macOS Key Vault certs as Exportable only so private key survives export On macOS, loading the Key Vault PKCS#12 with PersistKeySet imports the private key into the login Keychain, which cannot export the private key back out. That produced public-only PFX exports (~half the expected size) with no private key, breaking both the file-backed cert store and the base64 certs written to stdout. Select storage flags by OS: use Exportable only on macOS (no PersistKeySet) so the key stays in memory and can be exported to the file-backed store; keep Exportable | PersistKeySet on Windows/Linux. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/tools/CertHelper/KeyVaultCert.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/tools/CertHelper/KeyVaultCert.cs b/src/tools/CertHelper/KeyVaultCert.cs index e6fd7d73630..05d031d05f5 100644 --- a/src/tools/CertHelper/KeyVaultCert.cs +++ b/src/tools/CertHelper/KeyVaultCert.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; @@ -149,10 +150,18 @@ private async Task FindCertificateInKeyVaultAsync(string certN throw new Exception("Certificate secret not found in Key Vault"); } var certBytes = Convert.FromBase64String(secret.Value.Value); + + // On macOS, PersistKeySet imports the private key into the login Keychain, which then cannot + // export the private key back out (the same limitation the file-backed store works around). + // That produces public-only PFX exports (roughly half the expected size). Load the key as + // Exportable only so it stays in memory and can be exported to the file-backed store. + var storageFlags = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) + ? X509KeyStorageFlags.Exportable + : X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet; #if NET9_0_OR_GREATER - var cert = X509CertificateLoader.LoadPkcs12(certBytes, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); + var cert = X509CertificateLoader.LoadPkcs12(certBytes, "", storageFlags); #else - var cert = new X509Certificate2(certBytes, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); + var cert = new X509Certificate2(certBytes, "", storageFlags); #endif return cert; }