Skip to content

Use fail-open certificate revocation check in AzureDevOpsTask#16280

Merged
premun merged 8 commits intomainfrom
copilot/update-certificate-revocation-setting
Nov 10, 2025
Merged

Use fail-open certificate revocation check in AzureDevOpsTask#16280
premun merged 8 commits intomainfrom
copilot/update-certificate-revocation-setting

Conversation

Copy link
Contributor

Copilot AI commented Nov 7, 2025

Certificate revocation list (CRL) checks cause widespread build failures on macOS where CRL endpoints are inaccessible (dotnet/dnceng#6410). This change implements a fail-open certificate revocation check that maintains security while handling unknown revocation status gracefully.

Changes

  • Implemented secure fail-open pattern using SocketsHttpHandler with fine-grained X509ChainPolicy for .NET (Core/5+)
  • Added System.Security.Cryptography.X509Certificates namespace for certificate chain policy
  • Preserved AllowAutoRedirect = false setting
  • Added comprehensive comments documenting the rationale and linking to tracking issue
  • Removed accidentally added .nuget/nuget.exe file
#if NET
using SocketsHttpHandler handler = new SocketsHttpHandler
{
    AllowAutoRedirect = false,
};
handler.SslOptions.CertificateChainPolicy = new X509ChainPolicy
{
    RevocationMode = X509RevocationMode.Online,
    RevocationFlag = X509RevocationFlag.ExcludeRoot,
    VerificationFlags =
        X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown |
        X509VerificationFlags.IgnoreEndRevocationUnknown,
    VerificationTimeIgnored = true,
};
using (var client = new HttpClient(handler)
#else
using (var client = new HttpClient(new HttpClientHandler
{
    AllowAutoRedirect = false,
    CheckCertificateRevocationList = true,
})
#endif

Security behavior:

  • Certificate revocation checks are still performed - revoked certificates will fail validation
  • Unknown revocation status is handled gracefully - addresses macOS CRL endpoint issues without compromising security
  • More secure than completely disabling checks - uses targeted flags to ignore only unknown status, not actual revocations

Behavior by framework:

  • .NET (Core/5+): Uses SocketsHttpHandler with fine-grained verification flags for fail-open behavior
  • .NET Framework: Uses standard HttpClientHandler with full revocation checks enabled

This approach follows the established pattern from DownloadFile.cs and recommendations from security experts.

To double check:

[!WARNING]

This pull request was created as a result of the following prompt from Copilot chat.

In the AzureDevOpsTask.cs file located at src/Microsoft.DotNet.Helix/Sdk/AzureDevOpsTask.cs, the HttpClientHandler currently sets CheckCertificateRevocationList = true. To improve build reliability in environments where the CRL may not be accessible, update the code to set CheckCertificateRevocationList = false. Update any comments if necessary to explain the rationale. Ensure that no other code path enables revocation checks in the HttpClientHandler instance used by this class.

Original prompt

In the AzureDevOpsTask.cs file located at src/Microsoft.DotNet.Helix/Sdk/AzureDevOpsTask.cs, the HttpClientHandler currently sets CheckCertificateRevocationList = true. To improve build reliability in environments where the CRL may not be accessible, update the code to set CheckCertificateRevocationList = false. Update any comments if necessary to explain the rationale. Ensure that no other code path enables revocation checks in the HttpClientHandler instance used by this class.

This pull request was created as a result of the following prompt from Copilot chat.

In the AzureDevOpsTask.cs file located at src/Microsoft.DotNet.Helix/Sdk/AzureDevOpsTask.cs, the HttpClientHandler currently sets CheckCertificateRevocationList = true. To improve build reliability in environments where the CRL may not be accessible, update the code to set CheckCertificateRevocationList = false. Update any comments if necessary to explain the rationale. Ensure that no other code path enables revocation checks in the HttpClientHandler instance used by this class.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits November 7, 2025 18:28
Updated comment to clarify reason for disabling certificate revocation checks.
{
AllowAutoRedirect = false,
CheckCertificateRevocationList = true,
// Certificate revocation checks are disabled due to widespread failre on Ma
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Can we disable this only for Mac?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Certificate revocation checks are now only disabled on macOS using !RuntimeInformation.IsOSPlatform(OSPlatform.OSX). On Windows and Linux, the checks remain enabled. (4ea705a)

Copilot AI changed the title [WIP] Update HttpClientHandler to not check certificate revocation list Disable certificate revocation checks in AzureDevOpsTask Nov 7, 2025
Copilot AI requested a review from agocke November 7, 2025 18:45
Copilot AI changed the title Disable certificate revocation checks in AzureDevOpsTask Disable certificate revocation checks on macOS in AzureDevOpsTask Nov 7, 2025
@agocke agocke marked this pull request as ready for review November 7, 2025 18:55
@ericstj
Copy link
Member

ericstj commented Nov 7, 2025

Does this open up our requests to someone spoofing AzDo with a revoked certificate? Any risk here to disabling this? @bartonjs was suggesting a more targeted disabling of just X509VerificationFlags.IgnoreEndRevocationUnknown | X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown and VerificationTimeIgnored = true

@ericstj ericstj requested a review from bartonjs November 7, 2025 20:13
@ericstj
Copy link
Member

ericstj commented Nov 7, 2025

It looks like we had the better fix here --

#if NET
using SocketsHttpHandler handler = new SocketsHttpHandler();
handler.SslOptions.CertificateChainPolicy = new X509ChainPolicy
{
// Yes, check revocation.
// Yes, allow it to be downloaded if needed.
// Online is the default, but it doesn't hurt to be explicit.
RevocationMode = X509RevocationMode.Online,
// Roots never bother with revocation.
// ExcludeRoot is the default, but it doesn't hurt to be explicit.
RevocationFlag = X509RevocationFlag.ExcludeRoot,
// RevocationStatusUnknown at the EndEntity/Leaf certificate will not fail the chain build.
// RevocationStatusUnknown for any intermediate CA will not fail the chain build.
// IgnoreRootRevocationUnknown could also be specified, but it won't apply given ExcludeRoot above.
// The default is that all status codes are bad, this is not the default.
VerificationFlags =
X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown |
X509VerificationFlags.IgnoreEndRevocationUnknown,
// Always use the "now" when building the chain, rather than the "now" of when this policy object was constructed.
VerificationTimeIgnored = true,
};
using (var httpClient = new HttpClient(handler))
#else
using (var httpClient = new HttpClient(new HttpClientHandler { CheckCertificateRevocationList = true }))
#endif

@mmitche added, mentioning it was for mac in 346db01

@copilot can you improve this to use the method in the linked code, preserving the other AllowAutoRedirect that is set by this handler.

@agocke
Copy link
Member

agocke commented Nov 7, 2025

@copilot respond to comments

Copy link
Contributor Author

Copilot AI commented Nov 7, 2025

It looks like we had the better fix here --

#if NET
using SocketsHttpHandler handler = new SocketsHttpHandler();
handler.SslOptions.CertificateChainPolicy = new X509ChainPolicy
{
// Yes, check revocation.
// Yes, allow it to be downloaded if needed.
// Online is the default, but it doesn't hurt to be explicit.
RevocationMode = X509RevocationMode.Online,
// Roots never bother with revocation.
// ExcludeRoot is the default, but it doesn't hurt to be explicit.
RevocationFlag = X509RevocationFlag.ExcludeRoot,
// RevocationStatusUnknown at the EndEntity/Leaf certificate will not fail the chain build.
// RevocationStatusUnknown for any intermediate CA will not fail the chain build.
// IgnoreRootRevocationUnknown could also be specified, but it won't apply given ExcludeRoot above.
// The default is that all status codes are bad, this is not the default.
VerificationFlags =
X509VerificationFlags.IgnoreCertificateAuthorityRevocationUnknown |
X509VerificationFlags.IgnoreEndRevocationUnknown,
// Always use the "now" when building the chain, rather than the "now" of when this policy object was constructed.
VerificationTimeIgnored = true,
};
using (var httpClient = new HttpClient(handler))
#else
using (var httpClient = new HttpClient(new HttpClientHandler { CheckCertificateRevocationList = true }))
#endif

@mmitche ad...

Improved to use the fail-open pattern from DownloadFile.cs with fine-grained X509VerificationFlags that only ignore unknown revocation status rather than disabling all checks. Preserved AllowAutoRedirect = false. (087f1c7)

Does this open up our requests to someone spoofing AzDo with a revoked certificate? Any risk here to disabling this? @bartonjs was suggesting a more targeted disabling of just `X509VerificationFlags...

Good point. I've updated to use the more secure fail-open approach with IgnoreEndRevocationUnknown | IgnoreCertificateAuthorityRevocationUnknown and VerificationTimeIgnored = true. This still validates revoked certificates but handles unknown status gracefully. (087f1c7)

Copilot AI changed the title Disable certificate revocation checks on macOS in AzureDevOpsTask Use fail-open certificate revocation check in AzureDevOpsTask Nov 7, 2025
Copilot AI requested a review from agocke November 7, 2025 21:47
ericstj
ericstj previously approved these changes Nov 7, 2025
bartonjs
bartonjs previously approved these changes Nov 7, 2025
@bartonjs
Copy link
Member

bartonjs commented Nov 7, 2025

I don't know why the PR includes a new copy of nuget.exe, but the cert-related code looks good.

@agocke
Copy link
Member

agocke commented Nov 7, 2025

@copilot Delete copy of nuget.exe

Copilot AI dismissed stale reviews from bartonjs and ericstj via 832c1b9 November 7, 2025 23:00
Copy link
Contributor Author

Copilot AI commented Nov 7, 2025

@copilot Delete copy of nuget.exe

Removed the accidentally added nuget.exe file. (832c1b9)

@agocke agocke enabled auto-merge (squash) November 7, 2025 23:17
@ericstj
Copy link
Member

ericstj commented Nov 10, 2025

/ba-g android timeout in running helix work items (after submitting job - so it's past the portion changed by this PR)

@premun premun disabled auto-merge November 10, 2025 09:56
@premun premun merged commit 3a7f017 into main Nov 10, 2025
11 of 14 checks passed
@premun premun deleted the copilot/update-certificate-revocation-setting branch November 10, 2025 09:57
ericstj pushed a commit to ericstj/arcade that referenced this pull request Nov 13, 2025
…#16280)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: agocke <[email protected]>
Co-authored-by: Andy Gocke <[email protected]>
ericstj pushed a commit to ericstj/arcade that referenced this pull request Nov 13, 2025
…#16280)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: agocke <[email protected]>
Co-authored-by: Andy Gocke <[email protected]>
ericstj pushed a commit to ericstj/arcade that referenced this pull request Nov 13, 2025
…#16280)

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: agocke <[email protected]>
Co-authored-by: Andy Gocke <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants