Skip to content

Use DateTimeOffset.Now for checking certificate validity#12680

Merged
danegsta merged 4 commits intodotnet:mainfrom
danegsta:danegsta/dateTimeOffset
Nov 5, 2025
Merged

Use DateTimeOffset.Now for checking certificate validity#12680
danegsta merged 4 commits intodotnet:mainfrom
danegsta:danegsta/dateTimeOffset

Conversation

@danegsta
Copy link
Member

@danegsta danegsta commented Nov 4, 2025

Description

ASP.NET uses DateTimeOffset.Now to compare the current time against certificate not before/not after fields. Update our check to do the same. Otherwise we're comparing a DateTime value (in UTC) against a DateTimeOffset value is resulting in the DateTime value being incorrectly evaluated as a local time zone value in comparisons.

Additionally, the Windows certificate store considers some certificates as valid that OpenSSL doesn't, resulting in possible issues when loading certificates from the store into a language that uses OpenSSL, such as Python or Node. We were previously including all system certificates by default for Python, but this can result in errors on some systems. For now we'll revert to only trusting the developer certificate for OTEL purposes, with follow up work to use DCP to validate certificates for executables as well as containers.

Fixes #12618

@github-actions
Copy link
Contributor

github-actions bot commented Nov 4, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12680

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12680"

Copy link
Contributor

Copilot AI left a comment

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 changes the time value used for certificate validation from DateTime.UtcNow to DateTimeOffset.Now. The purpose is to align with the proper type for comparing against X509Certificate2's NotBefore and NotAfter properties.

Key Changes

  • Updated the now variable initialization in DeveloperCertificateService from DateTime.UtcNow to DateTimeOffset.Now

@danegsta
Copy link
Member Author

danegsta commented Nov 4, 2025

@mitchdenny @JamesNK can one or both of you try clearing your dev certs (dotnet dev-certs https --clean), trusting the dev cert again ``dotnet dev-certs https --trust), then dogfooding this PR to make sure we consider the certificate valid? You should be able to create any template, run with debug logging, and make sure that you don't see No ASP.NET Core developer certificates found in the CurrentUser/My certificate store.` in the log output.

We ran into a report of what seems to be a timezone related issue determining if the certificate is valid; this PR ensures we use the same DateTimeOffset.Now value that ASP.NET uses to generate and check the not before/not after times for the dev cert.

@danegsta danegsta added the area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication label Nov 4, 2025
@danegsta danegsta added this to the 13.0 milestone Nov 4, 2025
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var now = DateTime.UtcNow;
var now = DateTimeOffset.Now;
Copy link
Member

Choose a reason for hiding this comment

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

Add a comment saying why DateTimeOffset.Now is used. Link to eqivilent code in ASP.NET Core that's being followed.

Are there unit tests for this type? You'd probably need to pass in a TimeProvider to avoid changing time from interfering.

Copy link
Member Author

Choose a reason for hiding this comment

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

We don't currently have unit tests that validate the certificate not before/not after logic; ideally we'd be able to borrow some of the certificate creation logic from ASP.NET to validate properly. I've move the comment below this line up and added a reference to why we're using DateTimeOffset.Now.

// Configure required environment variables for custom certificate trust when running as an executable.
// TODO: Make CertificateTrustScope.System the default once we're able to validate that certificates are valid for OpenSSL. Otherwise we potentially add invalid certificates to the bundle which causes OpenSSL to error.
resourceBuilder
.WithCertificateTrustScope(CertificateTrustScope.System)
Copy link
Member Author

Choose a reason for hiding this comment

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

We ran into an issue with certificates that the certificate store and X509Certificate2 consider valid on Windows, but OpenSSL doesn't. This caused OpenSSL errors trying to validate HTTPS connections if they were present in the cert bundle for Python. DCP has the ability to do the necessary validation of a certificate to ensure it won't cause errors, but we'll need to add a new property for executables to be able to take advantage of it.

Until then, I'm switching Python back to the default trust scope of Append. That'll let us trust the OTEL connection, it just won't enable trusting the dev cert over arbitrary http clients.

@danegsta
Copy link
Member Author

danegsta commented Nov 5, 2025

There'll need to be follow up work to resolve the invalid certificates issue: #12693

@danegsta danegsta enabled auto-merge (squash) November 5, 2025 20:07
@danegsta
Copy link
Member Author

danegsta commented Nov 5, 2025

/backport to release/13.0

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

Started backporting to release/13.0: https://github.com/dotnet/aspire/actions/runs/19114831650

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

@danegsta backporting to "release/13.0" failed, the patch most likely resulted in conflicts:

$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Applying: Use DateTimeOffset.Now for checking certificate validity
Applying: Avoid loading all system certificates until we can validate them via DCP
Using index info to reconstruct a base tree...
M	src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
Falling back to patching base and 3-way merge...
Auto-merging src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
CONFLICT (content): Merge conflict in src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0002 Avoid loading all system certificates until we can validate them via DCP
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

@danegsta danegsta merged commit 9df422a into dotnet:main Nov 5, 2025
296 checks passed
@dotnet-policy-service dotnet-policy-service bot modified the milestones: 13.0, 13.1 Nov 5, 2025
@danegsta
Copy link
Member Author

danegsta commented Nov 5, 2025

/backport to release/13.0

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

Started backporting to release/13.0: https://github.com/dotnet/aspire/actions/runs/19116888141

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

@danegsta backporting to "release/13.0" failed, the patch most likely resulted in conflicts:

$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch

Applying: Use DateTimeOffset.Now for checking certificate validity
Applying: Avoid loading all system certificates until we can validate them via DCP
Using index info to reconstruct a base tree...
M	src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
Falling back to patching base and 3-way merge...
Auto-merging src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
CONFLICT (content): Merge conflict in src/Aspire.Hosting.Python/PythonAppResourceBuilderExtensions.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0002 Avoid loading all system certificates until we can validate them via DCP
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

danegsta added a commit to danegsta/aspire that referenced this pull request Nov 5, 2025
* Use DateTimeOffset.Now for checking certificate validity

* Avoid loading all system certificates until we can validate them via DCP

* Ensure comment covers usage of DateTimeOffset.Now as well
joperezr pushed a commit that referenced this pull request Nov 6, 2025
…2715)

* Use DateTimeOffset.Now for checking certificate validity

* Avoid loading all system certificates until we can validate them via DCP

* Ensure comment covers usage of DateTimeOffset.Now as well
@github-actions github-actions bot locked and limited conversation to collaborators Dec 6, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python starter app SSL and OTEL errors

4 participants