Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Normalize X509Chain App/Cert policies across OSes - #132348

Merged
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies
Aug 28, 2026
Merged

Normalize X509Chain App/Cert policies across OSes#132348
bartonjs merged 15 commits into
dotnet:mainfrom
bartonjs:normalize_cert_policies

Conversation

@bartonjs

Copy link
Copy Markdown
Member

The original policy handling code was written before contextual trust, which made it hard to write good tests. Now that we have more tests, unify the behaviors as best we can, even across invalidly encoded extensions.

Fixes#31246 (and maybe others)

The original policy handling code was written before contextual trust,
which made it hard to write good tests. Now that we have more tests,
unify the behaviors as best we can, even across invalidly encoded extensions.
@bartonjsbartonjs self-assigned this Aug 14, 2026
CopilotAI lite review requested due to automatic review settings August 14, 2026 23:30
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-libraries-coreclr outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates X509Chain policy processing so ApplicationPolicy/CertificatePolicy handling (and invalid/undecodable policy-related extensions) is evaluated and reported more consistently across Windows/OpenSSL/Apple/Android, and adjusts/expands tests to match the unified behavior.

Changes:

  • Refactors CertificatePolicyChain to compute per-chain-element “encoding” vs “usage” errors and exposes helpers to reuse the same logic across platform chain processors.
  • Updates OpenSSL, Apple, and Android chain processors to merge policy/encoding errors into chain + element status consistently (and to detect encoding issues even when no explicit policy filtering is requested).
  • Normalizes existing tests’ OS-conditional expectations and adds focused test suites for app-policy vs EKU behavior and corrupt policy-related extensions.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Security.Cryptography/tests/X509Certificates/RevocationTests/DynamicRevocationTests.csRemoves OS-conditional expectations for NotValidForUsage at non-leaf levels.
src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.csRefactors/makes helpers reusable by new tests; factors out shared DER encoding for policy extensions.
src/libraries/System.Security.Cryptography/tests/X509Certificates/CorruptPoliciesChainTests.csNew coverage for corrupt/undecodable policy/EKU-related extensions and expected chain-element status behavior.
src/libraries/System.Security.Cryptography/tests/X509Certificates/ChainTests.csNormalizes expectations around NotValidForUsage across platforms.
src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.csNew tests covering certificate policy constraints/mappings plus Application Policies vs EKU interactions.
src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csprojAdds the new test files to the test project.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.csSplits policy evaluation into “merge errors” and “process policy”; adds encoding-only validation when no policy filters are requested.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Apple.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.csSwitches to shared policy-chain logic and per-element error attribution.
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.csImplements CertificatePolicyChain.Build/CheckEncodingOnly, per-element error vectors, and revised EKU/app-policy semantics.
src/libraries/Common/src/System/Security/Cryptography/Oids.csAdds AnyEnhancedKeyUsage constant used in policy evaluation.

CopilotAI review requested due to automatic review settings August 18, 2026 21:51

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:661

  • ErrorVector's scalar bit test uses (1 << index) (an int shift). For indices >= 31 this overflows/sign-extends and will report the wrong bit, so long chains can misattribute policy/encoding errors to the wrong element.
 internal bool this[int index]
{
get
{
if (_vector is null)
{
return (_scalar & (1 << index)) != 0;
}

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • The comment about only checking EKU “for structural validity” when ApplicationCertPolicies is present but corrupt is misleading: this block currently skips EKU entirely whenever ApplicationCertPolicies is present (even if it failed to decode). Either update the comment to match the behavior, or add the intended validation call.
 if (policyData.EnhancedKeyUsage != null)
{
// If policyData.ApplicationCertPolicies is present, but corrupt, applicationCertPolicies
// should stay null, we'll only check EKU for structural validity.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

CopilotAI review requested due to automatic review settings August 18, 2026 22:10

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificatePolicy.cs:456

  • ReadExtendedKeyUsageExtension can throw CryptographicException on malformed EKU. In this code path (policy filtering active and no ApplicationCertPolicies extension), the exception is not caught, which would cause chain building to throw instead of reporting InvalidExtension/InvalidPolicyConstraints via encodingErrors.
 // should stay null.
if (policyData.ApplicationCertPolicies is null)
{
applicationCertPolicies = ReadExtendedKeyUsageExtension(policyData.EnhancedKeyUsage);
}

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:18

  • The RSATestData using-alias appears to be unused, which can trigger CS8019/IDE0005 in builds that enforce unused usings.
using RSATestData = System.Security.Cryptography.Rsa.Tests.TestData;

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/ChainPal.Android.cs:424

  • InvalidPolicyConstraints is being reported with SR.Chain_NoPolicyMatch, which describes a policy mismatch rather than a malformed/invalid extension. This can make X509ChainStatus.StatusInformation misleading for encoding failures.
 Status = X509ChainStatusFlags.InvalidPolicyConstraints,
// "NoPolicyMatch" says that the policy is "invalid", which works for this one, too.
StatusInformation = SR.Chain_NoPolicyMatch,

CopilotAI review requested due to automatic review settings August 18, 2026 22:20
CopilotAI review requested due to automatic review settings August 21, 2026 18:19

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

The "AppPol=NULL(05 00) critical EKU=Server; req=Server" test case is the only one that set the critical bit, and it failed with PartialChain on Android.
Logic dictates that it failed because Android doesn't support that extension, and it's marked as critical.
Rather than giving it a platform-dependent expected value, just delete the case.
CopilotAI review requested due to automatic review settings August 26, 2026 22:48
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/azp run runtime-extra-platforms

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (2) — in code that hasn't changed since the last review.

src/libraries/System.Security.Cryptography/tests/X509Certificates/DynamicChainTests.cs:1147

  • Use UtcNow instead of Now for certificate validity timestamps to avoid time zone/DST sensitivity in CI and local runs.
 DateTimeOffset notBefore = DateTimeOffset.Now.AddMinutes(-5);

src/libraries/System.Security.Cryptography/tests/X509Certificates/AppAndCertPoliciesChainTests.cs:235

  • Remove trailing whitespace in this initializer (it can cause noisy diffs and violates common formatting expectations).
 X509BasicConstraintsExtension.CreateForCertificateAuthority(), 

@bartonjs

Copy link
Copy Markdown
MemberAuthor

I've trawled the logs, and I attest, to the best of my ability, that none of the extra-platforms test failures are caused by this change.

(And I'm astounded at how many of them report failure when all tests passed and the runner script reports that it's returning success)

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/ba-g Many DeadLetters, other failures were investigated.

@bartonjs
bartonjs enabled auto-merge (squash) August 28, 2026 18:59
@bartonjs
bartonjs merged commit 4cd3d5c into dotnet:mainAug 28, 2026
10 of 46 checks passed
@bartonjs
bartonjs deleted the normalize_cert_policies branch August 28, 2026 19:02
@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport-to release/11.0

@bartonjs

Copy link
Copy Markdown
MemberAuthor

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

artl93 pushed a commit that referenced this pull request Aug 28, 2026
…2904)
Backport of #132348 to release/11.0
/cc @bartonjs
## Customer Impact
- [X] Customer reported
- [X] Found internally
Users of the X509Chain API could encounter platform-specific differences
regarding handling of the ChainPolicy.ApplicationPolicies and
ChainPolicy.CertificatePolicies validators and their interaction with
the ms-appPolicy, EKU, CertPolicy, and CertPolicyMapping extensions,
leading to the chain to report a certificate suitable for usage on some
systems while unsuitable for usage on others (both false-positives and
false-negatives).
Some certificates gave a solid true/false on Windows, but caused
exceptions on other platforms.
## Regression
- [ ] Yes
- [X] No
The managed certificate policy validator (which is trying to emulate
Windows for .NET Framework compatibility) hasn't substantially changed
since 2015.
## Testing
> How was the fix verified?
A whole lot of new tests are added in this change.
> How was the issue missed previously?
The component was written before the CertificateRequest API was created,
and at the time creating test certificates was a laborious process and
involved checking in test cases.
> What tests were added?
Many tests were added involving corrupt extensions, certificate policy
mappings, any-policy and inhibit-any-policy, et cetera. These new tests
are believed to be comprehensive for the area.
## Risk
Low, due to the added test coverage.
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
@dotnet-milestone-botdotnet-milestone-botBot added this to the 12.0-preview1 milestone Aug 29, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

X509Chain is not consistent with NotValidForUsage between Windows and Linux

3 participants

@bartonjs@vcsjones