From 1eca761a4c943c1b95fddeb4e19e3f3d3c4e2ce6 Mon Sep 17 00:00:00 2001 From: "Prabha S (ps)" Date: Thu, 4 Dec 2025 06:11:51 -0800 Subject: [PATCH 1/4] Reset the PreRelease --- pipeline-templates/global-variables.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pipeline-templates/global-variables.yml b/pipeline-templates/global-variables.yml index 3e0bbcf..4acbfc9 100644 --- a/pipeline-templates/global-variables.yml +++ b/pipeline-templates/global-variables.yml @@ -12,9 +12,9 @@ # azure pipeline Reached heap limit Allocation failed - JavaScript heap out of memory The command "npm install" exited with code 134 variables: - name: semanticVersion - value: "8.2.0" + value: "8.2.1" - name: isPrerelease - value: ${{ true }} + value: ${{ false }} - name: isReleaseBranch value: $[ or( eq(variables['Build.SourceBranch'], 'refs/heads/master'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release-') ) ] - name: NODE_OPTIONS From af4d18aa928e439b2cf1516b8c1fc9e5d44afe22 Mon Sep 17 00:00:00 2001 From: Palwinder Singh Date: Tue, 6 Jan 2026 23:59:36 -0800 Subject: [PATCH 2/4] TFS #650905: [BUG] [VKB) - Secrets Broker: Certificate Upload is Broken Added check for both encoding pcks12 and PEM encoding --- .../ConfigDb/LiteDbConfigurationRepository.cs | 5 ++- .../Extensions/CertificateExtensions.cs | 38 +++++++++++++++++++ .../Logic/CertificateData.cs | 3 +- .../Logic/SafeguardLogic.cs | 4 +- 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 SafeguardDevOpsService/Extensions/CertificateExtensions.cs diff --git a/SafeguardDevOpsService/ConfigDb/LiteDbConfigurationRepository.cs b/SafeguardDevOpsService/ConfigDb/LiteDbConfigurationRepository.cs index 86affdc..e1a467a 100644 --- a/SafeguardDevOpsService/ConfigDb/LiteDbConfigurationRepository.cs +++ b/SafeguardDevOpsService/ConfigDb/LiteDbConfigurationRepository.cs @@ -12,6 +12,7 @@ using OneIdentity.DevOps.Data; using OneIdentity.DevOps.Data.Spp; using OneIdentity.DevOps.Exceptions; +using OneIdentity.DevOps.Extensions; using OneIdentity.DevOps.Logic; using CredentialType = CredentialManagement.CredentialType; @@ -653,7 +654,7 @@ public X509Certificate2 UserCertificate try { var bytes = Convert.FromBase64String(UserCertificateBase64Data); - var cert = X509CertificateLoader.LoadPkcs12(bytes, UserCertificatePassphrase); + var cert = CertificateExtensions.LoadFromBytes(bytes,UserCertificatePassphrase); return cert; } catch (Exception) @@ -699,7 +700,7 @@ public X509Certificate2 WebSslCertificate try { var bytes = Convert.FromBase64String(WebSslCertificateBase64Data); - var cert = X509CertificateLoader.LoadPkcs12(bytes, WebSslCertificatePassphrase); + var cert = CertificateExtensions.LoadFromBytes(bytes, WebSslCertificatePassphrase); return cert; } catch (Exception) diff --git a/SafeguardDevOpsService/Extensions/CertificateExtensions.cs b/SafeguardDevOpsService/Extensions/CertificateExtensions.cs new file mode 100644 index 0000000..c4a08fd --- /dev/null +++ b/SafeguardDevOpsService/Extensions/CertificateExtensions.cs @@ -0,0 +1,38 @@ +using System.Security.Cryptography.X509Certificates; +using System.Text; + +namespace OneIdentity.DevOps.Extensions +{ + public static class CertificateExtensions + { + public static X509Certificate2 LoadFromBytes(byte[] rawData, string? password = null, X509KeyStorageFlags? keyStorageFlags = null) + { + // 1. Detect if the byte array is PKCS12 or PEM + X509ContentType contentType = X509Certificate2.GetCertContentType(rawData); + + if (contentType == X509ContentType.Pkcs12) + { + if (keyStorageFlags.HasValue) + { + // Use the new .NET 9 Loader for binary PKCS12/PFX + return X509CertificateLoader.LoadPkcs12(rawData, password, keyStorageFlags.Value); + } + else + { + // Use the new .NET 9 Loader for binary PKCS12/PFX + return X509CertificateLoader.LoadPkcs12(rawData, password); + } + + } + else + { + // It's likely PEM (text-based). + // We convert the bytes to a string to use the PEM parser. + string pemString = Encoding.UTF8.GetString(rawData); + + // This works if the PEM contains both the CERTIFICATE and PRIVATE KEY + return X509Certificate2.CreateFromPem(pemString); + } + } + } +} diff --git a/SafeguardDevOpsService/Logic/CertificateData.cs b/SafeguardDevOpsService/Logic/CertificateData.cs index 94a35ef..7f9bae2 100644 --- a/SafeguardDevOpsService/Logic/CertificateData.cs +++ b/SafeguardDevOpsService/Logic/CertificateData.cs @@ -4,6 +4,7 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using OneIdentity.DevOps.Exceptions; +using OneIdentity.DevOps.Extensions; namespace OneIdentity.DevOps.Logic { @@ -16,7 +17,7 @@ internal class CertificateData : ICertificateData, IDisposable public CertificateData(string certB64, string password) { Password = password; - cert = X509CertificateLoader.LoadPkcs12(Convert.FromBase64String(certB64), password, X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.Exportable); + cert = CertificateExtensions.LoadFromBytes(Convert.FromBase64String(certB64), password, X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.Exportable); } public string Base64Certificate => Convert.ToBase64String(cert.Export(X509ContentType.Cert)); diff --git a/SafeguardDevOpsService/Logic/SafeguardLogic.cs b/SafeguardDevOpsService/Logic/SafeguardLogic.cs index fc128b1..db1b76b 100644 --- a/SafeguardDevOpsService/Logic/SafeguardLogic.cs +++ b/SafeguardDevOpsService/Logic/SafeguardLogic.cs @@ -1640,7 +1640,7 @@ public void InstallCertificate(CertificateInfo certificate, CertificateType cert X509Certificate2 cert; try { - cert = X509CertificateLoader.LoadPkcs12(certificateBytes, certificate.Passphrase); + cert = CertificateExtensions.LoadFromBytes(certificateBytes, certificate.Passphrase); _logger.Debug( $"Parsed certificate for installation: subject={cert.SubjectName.Name}, thumbprint={cert.Thumbprint}"); } @@ -2304,7 +2304,7 @@ private CertificateInfo AddTrustedCertificate(string base64CertificateData, stri try { var certificateBytes = CertificateHelper.ConvertPemToData(base64CertificateData); - var cert = X509CertificateLoader.LoadPkcs12(certificateBytes, passPhrase); + var cert = CertificateExtensions.LoadFromBytes(certificateBytes, passPhrase); _logger.Debug( $"Parsed new trusted certificate: subject={cert.SubjectName}, thumbprint={cert.Thumbprint}."); From 00c75b29f24e34d2e469f49049dd98fd715eab43 Mon Sep 17 00:00:00 2001 From: Palwinder Singh Date: Thu, 8 Jan 2026 05:47:13 -0800 Subject: [PATCH 3/4] TFS #650905: [BUG] [VKB) - Secrets Broker: Certificate Upload is Broken Added check for both encoding pcks12 and PEM encoding --- .../Extensions/CertificateExtensions.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/SafeguardDevOpsService/Extensions/CertificateExtensions.cs b/SafeguardDevOpsService/Extensions/CertificateExtensions.cs index c4a08fd..8ee98d4 100644 --- a/SafeguardDevOpsService/Extensions/CertificateExtensions.cs +++ b/SafeguardDevOpsService/Extensions/CertificateExtensions.cs @@ -1,4 +1,5 @@ -using System.Security.Cryptography.X509Certificates; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; using System.Text; namespace OneIdentity.DevOps.Extensions @@ -30,8 +31,21 @@ public static X509Certificate2 LoadFromBytes(byte[] rawData, string? password = // We convert the bytes to a string to use the PEM parser. string pemString = Encoding.UTF8.GetString(rawData); - // This works if the PEM contains both the CERTIFICATE and PRIVATE KEY - return X509Certificate2.CreateFromPem(pemString); + // 1. Load the public certificate + var cert = X509CertificateLoader.LoadCertificate(rawData); + + // 2. Load the private key if it exists in the string + if (pemString.Contains("PRIVATE KEY")) + { + using var rsa = RSA.Create(); + // ImportFromPem automatically handles both 'Universal 2' and 'Universal 16' + rsa.ImportFromPem(pemString); + + // 3. Link them together + return cert.CopyWithPrivateKey(rsa); + } + + return cert; } } } From 3f4de5f66487311ea34a9ffb72c62839438542e0 Mon Sep 17 00:00:00 2001 From: Palwinder Singh Date: Tue, 13 Jan 2026 02:08:37 -0800 Subject: [PATCH 4/4] Update version variable as 8.2.2 --- pipeline-templates/global-variables.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pipeline-templates/global-variables.yml b/pipeline-templates/global-variables.yml index 4acbfc9..19cf25a 100644 --- a/pipeline-templates/global-variables.yml +++ b/pipeline-templates/global-variables.yml @@ -12,7 +12,7 @@ # azure pipeline Reached heap limit Allocation failed - JavaScript heap out of memory The command "npm install" exited with code 134 variables: - name: semanticVersion - value: "8.2.1" + value: "8.2.2" - name: isPrerelease value: ${{ false }} - name: isReleaseBranch