Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
b04ebe1
MacOS Certificate Generator Fix
afifi-ins May 6, 2026
15048f5
Clean up macOS certificate store handling in CertificateGenerator
afifi-ins May 7, 2026
dd6b5ea
Handle macOS certificate stores proactively
afifi-ins May 7, 2026
2556a07
Use custom keychain for all macOS cert operations
afifi-ins May 8, 2026
56e5581
Fix PKCS12 format for macOS compatibility
afifi-ins May 8, 2026
ca1993d
Fix macOS PFX loading: bypass X509Certificate2 constructor, use CLI i…
afifi-ins May 8, 2026
2a88cdb
Fix macOS: skip X509Certificate2 creation entirely for non-authority …
afifi-ins May 8, 2026
bdac14f
Fix NullReferenceException in InstallCertificateToMyStore on macOS
afifi-ins May 8, 2026
40930a1
Fix null server certificate on macOS: set default keychain and retrie…
afifi-ins May 8, 2026
9502aae
Fix macOS: use openssl to create compatible PFX instead of BouncyCastle
afifi-ins May 8, 2026
b815fa2
Drop BouncyCastle, use .NET CertificateRequest API for cert generation
afifi-ins May 8, 2026
93f3531
Fix macOS keychain error and Linux notBefore validation in cert gener…
afifi-ins May 9, 2026
f6ed657
Restore PFX round-trip on Windows/Linux for key persistence
afifi-ins May 11, 2026
09ef6c1
Match original cert config: add MachineKeySet flag, set FriendlyName …
afifi-ins May 11, 2026
418ac3f
Suppress CA1416 for guarded FriendlyName setter
afifi-ins May 11, 2026
b462504
macOS: route all store names to My in GetX509Store so installs and lo…
afifi-ins May 11, 2026
b1537e2
macOS: always import PFX with private key when available
afifi-ins May 11, 2026
1dcd551
macOS: relax CertificateFromSubject lookup to validOnly:false
afifi-ins May 12, 2026
184b308
Skip Https_SecModeTransWithMessCred_UserNameClientCredential_Succeeds…
afifi-ins May 12, 2026
879620a
Clean up unused cert helper code and diagnostic logging
afifi-ins May 13, 2026
ccb645b
Update scripts to call CertificateGenerator from net10.0 output path
afifi-ins May 13, 2026
ecdcc9e
Replace OID string constants with strongly-typed Oid fields
afifi-ins May 13, 2026
8ff5886
Use built-in X509AuthorityKeyIdentifierExtension and SubjectAlternati…
afifi-ins May 13, 2026
9320162
Use CertificateRevocationListBuilder for CRL generation
afifi-ins May 13, 2026
97de87a
Simplify hex/serial helpers with built-in Convert + BigInteger APIs
afifi-ins May 13, 2026
d117462
Use 'command -v' instead of 'which' in InstallRootCertificate.sh
afifi-ins May 13, 2026
dfc3b66
Fix CRL revocation entry serial encoding for high-bit serials
afifi-ins May 13, 2026
ec11ca8
Fix macOS cert install / partial-trust for issue #2870
afifi-ins May 20, 2026
d3fcf1b
Issue #2870: fix macOS root cert partial trust with -p ssl
afifi-ins May 20, 2026
9c72ada
macOS CI: default ServiceHost to localhost for cert install
afifi-ins May 20, 2026
5e8274e
Fix invalid XML comment in SendToHelix.proj
afifi-ins May 20, 2026
e765d5e
macOS Helix: pre-create login keychain for client cert install
afifi-ins May 20, 2026
c477664
macOS Helix: delete existing login keychain before recreating
afifi-ins May 20, 2026
fcecdf2
macOS: install root cert trust into System.keychain admin domain via …
afifi-ins May 20, 2026
53952b5
Rerun CI
afifi-ins May 20, 2026
f9ed34c
Retrigger CI - macOS Helix queue was saturated previously
afifi-ins May 20, 2026
a365438
Retrigger CI
afifi-ins May 22, 2026
8d2c435
macOS: add trust diagnostics + temporarily skip Linux/Windows legs
afifi-ins May 22, 2026
d5379b1
macOS: drop -p ssl trust policy + add .NET X509Chain diagnostic
afifi-ins May 22, 2026
dca0ce3
Use X509CertificateLoader to fix SYSLIB0057 (warnings-as-errors)
afifi-ins May 22, 2026
f03555e
macOS: skip custom-keychain root import; admin-trust System.keychain …
afifi-ins May 22, 2026
4650fc8
macOS: add X509Chain leaf cert diagnostic
afifi-ins May 22, 2026
bec0464
Set RevocationMode=NoCheck on the 4 remaining macOS-failing tests
afifi-ins May 22, 2026
7f60d87
Add missing using System.Security.Cryptography.X509Certificates in Ht…
afifi-ins May 22, 2026
ad7010c
Test infra: add macOS System.keychain admin trust for remote server r…
afifi-ins May 22, 2026
59b4a71
Re-run CI after wcfcoresrv23 outage
afifi-ins May 22, 2026
5ee77ea
Drop CRL DP from generated leaf certs; revert per-test RevocationMode…
afifi-ins May 23, 2026
1ed7042
Revert leaf CRL DP drop; re-add RevocationMode=NoCheck on 4 macOS tests
afifi-ins May 23, 2026
d002066
Revert RevocationMode=NoCheck; add macOS trust install diagnostics
afifi-ins May 23, 2026
d218e51
macOS: also seed .NET user-root store with wcfcoresrv23 root cert
afifi-ins May 23, 2026
e98bc9e
Fix MSBuild parse error in macOS pre-command: use backticks for cmd s…
afifi-ins May 23, 2026
150874f
macOS: drop dead user-root PFX seed; refresh trustd; remove -p ssl na…
afifi-ins May 23, 2026
ce3066a
macOS: add AIA OCSP URL + tryLater OCSP responder for ChainTrust test
afifi-ins May 24, 2026
bf1778b
macOS: replace tryLater OCSP stub with CA-signed BasicOCSPResponse
afifi-ins May 24, 2026
4107ee9
PRService: re-mint server certs when PR changes cert source
afifi-ins May 25, 2026
b1fff8b
Accept OCSP requests with payload in URL path (RFC 6960 A.1.1)
afifi-ins May 25, 2026
f7fad98
Return revoked status in OCSP response for revoked test certs
afifi-ins May 25, 2026
d34e1fe
Drop OCSP path; rely on CRL with trustd cache pre-warm on macOS
afifi-ins Jun 5, 2026
c876e71
Move CRL cache warming into CertificateHelper.ImportCertToMacOSKeychain
afifi-ins Jun 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion azure-pipelines-arcade-PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ stages:
helixRepo: dotnet/wcf
jobs:
- job: Windows
condition: false # TEMP: macos-cert-issue branch — skip Windows leg for faster iteration on macOS-only changes
timeoutInMinutes: 90
pool:
${{ if eq(variables._RunAsPublic, True) }}:
Expand Down Expand Up @@ -142,6 +143,7 @@ stages:
# Only build and test Linux in PR and CI builds.
- ${{ if eq(variables._RunAsPublic, True) }}:
- job: Linux
condition: false # TEMP: macos-cert-issue branch — skip Linux leg for faster iteration on macOS-only changes
timeoutInMinutes: 90
container: ubuntu_2204
pool:
Expand Down Expand Up @@ -210,7 +212,6 @@ stages:
# Only build and test MacOS in PR and CI builds.
- ${{ if eq(variables._RunAsPublic, True) }}:
- job: MacOS
condition: ne(variables._RunWithCoreWcfService, True)
timeoutInMinutes: 90
pool:
name: NetCore-Public
Expand Down
15 changes: 15 additions & 0 deletions eng/SendToHelix.proj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,21 @@
<HelixPreCommands>$(HelixPreCommands);export OPENSSL_ENABLE_SHA1_SIGNATURES=1</HelixPreCommands>
</PropertyGroup>

<PropertyGroup Condition="'$(TestJob)' == 'MacOS'" >
<!-- Helix macOS workers run as the non-interactive 'helix-runner' user. The
existing login keychain (if any) has a password we do not know, which leaves
it locked and causes X509Store(My, CurrentUser).Open(ReadWrite) to fail with
errSecNoSuchKeychain / SecKeychainUnlock errors. Drop any pre-existing login
keychain and create a fresh one with an empty password so the test
infrastructure can install the client cert (dotnet/wcf#2870). -->
<HelixPreCommands>$(HelixPreCommands);security delete-keychain $HOME/Library/Keychains/login.keychain-db 2&gt;/dev/null || true</HelixPreCommands>
<HelixPreCommands>$(HelixPreCommands);security create-keychain -p "" $HOME/Library/Keychains/login.keychain-db</HelixPreCommands>
<HelixPreCommands>$(HelixPreCommands);security set-keychain-settings -lut 7200 $HOME/Library/Keychains/login.keychain-db</HelixPreCommands>
<HelixPreCommands>$(HelixPreCommands);security unlock-keychain -p "" $HOME/Library/Keychains/login.keychain-db</HelixPreCommands>
<HelixPreCommands>$(HelixPreCommands);security list-keychains -d user -s $HOME/Library/Keychains/login.keychain-db /Library/Keychains/System.keychain</HelixPreCommands>
<HelixPreCommands>$(HelixPreCommands);security default-keychain -d user -s $HOME/Library/Keychains/login.keychain-db</HelixPreCommands>
</PropertyGroup>

<PropertyGroup Condition="'$(TestJob)' == 'Windows' AND '$(RunWithCoreWCFService)' == 'true'">
<HelixPreCommands>$(HelixPreCommands);set PATH=%HELIX_CORRELATION_PAYLOAD%\dotnet-cli%3B%PATH%</HelixPreCommands>
<!-- %3B is an escaped ; -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
Expand Down Expand Up @@ -233,9 +234,75 @@ public static X509Certificate2 InstallCertificateToRootStore(X509Certificate2 ce
{
// See explanation of StoreLocation selection at PlatformSpecificRootStoreLocation
certificate = AddToStoreIfNeeded(StoreName.Root, PlatformSpecificRootStoreLocation, certificate);

// On macOS, .NET's X509Store(Root, *) does not establish OS-level trust required by SslStream/SecTrust.
// Add an admin trust setting to the System.keychain via the `security` CLI. Passwordless sudo is set up
// for the Helix work item via eng/SendToHelix.proj pre-commands.
if ((OSHelper.Current & OSID.OSX) == OSHelper.Current)
{
AddTrustedRootOnMacOS(certificate);
}

return certificate;
}

private static void AddTrustedRootOnMacOS(X509Certificate2 certificate)
{
string pemPath = Path.Combine(Path.GetTempPath(), "wcf-root-" + certificate.Thumbprint + ".pem");
try
{
byte[] der = certificate.Export(X509ContentType.Cert);
var sb = new StringBuilder();
sb.AppendLine("-----BEGIN CERTIFICATE-----");
string b64 = Convert.ToBase64String(der);
for (int i = 0; i < b64.Length; i += 64)
{
sb.AppendLine(b64.Substring(i, Math.Min(64, b64.Length - i)));
}
sb.AppendLine("-----END CERTIFICATE-----");
File.WriteAllText(pemPath, sb.ToString());

RunSecurity("sudo", "-n security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain \"" + pemPath + "\"");
}
catch (Exception ex)
{
Console.WriteLine("[CertificateManager] Failed to add macOS admin trust: " + ex);
}
finally
{
try { if (File.Exists(pemPath)) File.Delete(pemPath); } catch { }
}
}

private static void RunSecurity(string fileName, string arguments)
{
try
{
var psi = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
using (var p = Process.Start(psi))
{
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit(60000);
Console.WriteLine($"[CertificateManager] {fileName} {arguments} exit={p.ExitCode}");
if (!string.IsNullOrEmpty(stdout)) Console.WriteLine("[CertificateManager] stdout: " + stdout);
if (!string.IsNullOrEmpty(stderr)) Console.WriteLine("[CertificateManager] stderr: " + stderr);
}
}
catch (Exception ex)
{
Console.WriteLine($"[CertificateManager] Failed to run '{fileName} {arguments}': {ex}");
}
}

// Install the certificate into the My store.
// It will not install the certificate if it is already present in the store.
// It returns the thumbprint of the certificate, regardless whether it was added or found.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand Down Expand Up @@ -93,7 +93,6 @@ public void WindowsAuth()
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(SSL_Available))]
[OuterLoop]
private void BasicCertAsTransport()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand All @@ -14,7 +14,6 @@

public class WSFederationHttpBindingTests : ConditionalWcfTest
{
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available),
Expand Down Expand Up @@ -76,7 +75,6 @@ public static void WSFederationHttpBindingTests_Succeeds(MessageSecurityVersion
}
}

[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available),
Expand Down Expand Up @@ -128,7 +126,6 @@ public static void WSTrustTokeParameters_WSStaticHelper()
}
}

[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
Expand All @@ -8,7 +8,6 @@
public class BasicHttpTransportWithMessageCredentialSecurityTests : ConditionalWcfTest
{
[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
Expand Down Expand Up @@ -56,7 +55,6 @@ public static void BasicHttps_SecModeTransWithMessCred_CertClientCredential_Succ
}

[WcfTheory]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(SSL_Available))]
[OuterLoop]
Expand Down Expand Up @@ -107,7 +105,6 @@ public static void BasicHttps_SecModeTransWithMessCred_UserNameClientCredential_
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(SSL_Available))]
[OuterLoop]
Expand Down Expand Up @@ -156,7 +153,6 @@ public static void Https_SecModeTransWithMessCred_UserNameClientCredential_Succe
}

[WcfTheory]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(SSL_Available))]
[OuterLoop]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using Infrastructure.Common;
Expand All @@ -7,7 +7,6 @@
public class BasicHttpsTransportWithMessageCredentialSecurityTests : ConditionalWcfTest
{
[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// The .NET Foundation licenses this file to you under the MIT license.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
Expand All @@ -12,7 +12,6 @@
public class WS2007HttpTransportWithMessageCredentialsSecurityTests : ConditionalWcfTest
{
[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand All @@ -13,7 +13,6 @@
public class WSHttpTransportWithMessageCredentialSecurityTests : ConditionalWcfTest
{
[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand All @@ -15,7 +15,6 @@
public class WSNetTcpTransportWithMessageCredentialSecurityTests : ConditionalWcfTest
{
[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
Expand Down Expand Up @@ -63,7 +62,6 @@ public static void NetTcp_SecModeTransWithMessCred_CertClientCredential_Succeeds
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(SSL_Available))]
[OuterLoop]
Expand Down Expand Up @@ -112,7 +110,6 @@ public static void NetTcp_SecModeTransWithMessCred_UserNameClientCredential_Succ
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(SSL_Available))]
[OuterLoop]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public partial class HttpsTests : ConditionalWcfTest
[WcfTheory]
[InlineData(WSMessageEncoding.Text)]
[InlineData(WSMessageEncoding.Mtom)]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(Server_Accepts_Certificates),
Expand Down Expand Up @@ -221,7 +220,6 @@ public static void SameBinding_Soap12_EchoString()
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
Expand Down Expand Up @@ -269,7 +267,6 @@ public static void ServerCertificateValidation_EchoString()
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(SSL_Available))]
[OuterLoop]
public static async Task ServerCertificateValidationUsingIdentity_EchoString()
Expand Down Expand Up @@ -310,7 +307,6 @@ public static async Task ServerCertificateValidationUsingIdentity_EchoString()
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
[OuterLoop]
Expand Down Expand Up @@ -348,7 +344,6 @@ public static void ServerCertificateValidationUsingIdentity_Throws_EchoString()
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(Server_Accepts_Certificates),
Expand Down Expand Up @@ -398,7 +393,6 @@ public static void ClientCertificate_EchoString()
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(Server_Accepts_Certificates),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.


using System;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;
using Infrastructure.Common;
Expand Down Expand Up @@ -171,7 +172,6 @@ public static void Https_SecModeTrans_CertValMode_PeerOrChainTrust_Succeeds_Chai
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed),
nameof(Client_Certificate_Installed),
nameof(SSL_Available))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
public partial class Tcp_ClientCredentialTypeTests : ConditionalWcfTest
{
[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed), nameof(Client_Certificate_Installed))]
[OuterLoop]
public static void TcpClientCredentialType_Certificate_EchoString()
Expand Down Expand Up @@ -62,7 +61,6 @@ public static void TcpClientCredentialType_Certificate_EchoString()
}

[WcfFact]
[Issue(2870, OS = OSID.OSX)]
[Condition(nameof(Root_Certificate_Installed), nameof(Client_Certificate_Installed))]
[OuterLoop]
public static void TcpClientCredentialType_Certificate_CustomValidator_EchoString()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net471</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>

Expand All @@ -10,7 +10,7 @@
</ItemGroup>

<ItemGroup>
<Reference Include="System.Configuration" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.0" />
</ItemGroup>

</Project>
Loading
Loading