Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading PFX without admin causes CryptographicException #110217

Open
timmac-qmc opened this issue Nov 27, 2024 · 12 comments
Open

Loading PFX without admin causes CryptographicException #110217

timmac-qmc opened this issue Nov 27, 2024 · 12 comments

Comments

@timmac-qmc
Copy link

timmac-qmc commented Nov 27, 2024

Description

After upgrading to .Net 9.0 on a API project the following codes throws the error "System.Security.Cryptography.CryptographicException: 'Access denied.'" when not run as Admin. This works fine without admin on .net 8.0.

builder.WebHost.UseKestrel(options =>
{
    options.ListenAnyIP(443, builder =>
    {
            builder.UseHttps("D:\\private_cert.pfx", "password");
    });
});

Reproduction Steps

  1. Create a new .Net 9.0 API project.
  2. In Program.cs load a certifcate using the code provided

Expected behavior

Project runs without issue

Actual behavior

Exception thrown: System.Security.Cryptography.CryptographicException: 'Access denied.'

 	System.Security.Cryptography.dll!System.Security.Cryptography.X509Certificates.X509CertificateLoader.ImportPfx(System.ReadOnlySpan<byte> data, System.ReadOnlySpan<char> password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags)	Unknown
 	System.Security.Cryptography.dll!System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadPkcs12NoLimits(System.ReadOnlyMemory<byte> data, System.ReadOnlySpan<char> password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, ref System.Security.Cryptography.X509Certificates.X509CertificateLoader.Pkcs12Return earlyReturn)	Unknown
 	System.Security.Cryptography.dll!System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadPkcs12(System.ReadOnlyMemory<byte> data, System.ReadOnlySpan<char> password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Security.Cryptography.X509Certificates.Pkcs12LoaderLimits loaderLimits)	Unknown
 	System.Security.Cryptography.dll!System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadFromFile<System.Security.Cryptography.X509Certificates.X509CertificateLoader.Pkcs12Return>(string path, System.ReadOnlySpan<char> password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Security.Cryptography.X509Certificates.Pkcs12LoaderLimits loaderLimits, System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadFromFileFunc<System.Security.Cryptography.X509Certificates.X509CertificateLoader.Pkcs12Return> loader)	Unknown
 	System.Security.Cryptography.dll!System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadPkcs12PalFromFile(string path, System.ReadOnlySpan<char> password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags, System.Security.Cryptography.X509Certificates.Pkcs12LoaderLimits loaderLimits)	Unknown
 	System.Security.Cryptography.dll!System.Security.Cryptography.X509Certificates.CertificatePal.FromBlobOrFile(System.ReadOnlySpan<byte> rawData, string fileName, Microsoft.Win32.SafeHandles.SafePasswordHandle password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags)	Unknown
 	System.Security.Cryptography.dll!System.Security.Cryptography.X509Certificates.X509Certificate.X509Certificate(string fileName, string password, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags keyStorageFlags)	Unknown
 	Microsoft.AspNetCore.Server.Kestrel.Core.dll!Microsoft.AspNetCore.Hosting.ListenOptionsHttpsExtensions.UseHttps(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions listenOptions, string fileName, string password)	Unknown
>	Program.<Main>$.AnonymousMethod__0_18(Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions builder) Line 52	C#

Regression?

Yes, works on .Net 8.0

Known Workarounds

No response

Configuration

.Net 9.0
Windows 11 26100.2314 x64

Other information

No response

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Nov 27, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones
See info in area-owners.md if you want to be subscribed.

@rabotond
Copy link

I am facing the same. Works on .net8 but exception on .net9. Running it with admin mode solves it.

@barrie-poultryplan
Copy link

Same issue here.

@jimitndiaye
Copy link

Same issue here: dotnet/aspnetcore#59300

@jeffhandley jeffhandley added this to the 9.0.x milestone Dec 5, 2024
@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Dec 5, 2024
@jeffhandley
Copy link
Member

@krwq Please investigate this. The repro in dotnet/aspnetcore#59300 looks like a good way to get started.

@DierkDroth
Copy link

DierkDroth commented Dec 8, 2024

I have a different scenario which is running into trouble with .NET9 and which is failing for potentially the same reason.

I understand that

X509Certificate2 certificate = new X509Certificate2(byte[] data, string password)

... now is obsolete with .NET9, which is why I replaced it by

X509Certificate2 certificate = X509CertificateLoader.LoadPkcs12(byte[] data, string password)

The certificate itself is used by the Kestrel server:

builder.WebHost.ConfigureKestrel(kestrel =>
{
	kestrel.ListenAnyIP(port, portOptions =>
	{
		portOptions.UseHttps(certificate);
	});
});

This works fine if the Kestrel server is running on the target (Linux) server. However, for development and debugging purposes I'm running the Kestrel server on my local Windows 11 machine as well where a SSH script reroutes the remote server port to my local machine.

Code above only works on my local machine if I'm running Visual Studio as administrator. The local Kestrel server can't be reached if running as non-admin.

Can you please confirm/deny that the source of trouble is the same as reports above?
Thanks in advance

@krwq
Copy link
Member

krwq commented Dec 9, 2024

@DierkDroth it's likely related to the same piece of code but IMO failing for different reason - it will be beneficial if you could share steps how to create cert similar to yours.

The simple repro for this issue is just this (ASP.NET is not needed):
new X509Certificate2("cert.pfx", "1234") (creating cert as described in dotnet/aspnetcore#59300) and it can be worked around simply with X509CertificateLoader.LoadPkcs12(File.ReadAllBytes("cert.pfx"), "1234"). I noticed that this is another way to repro:

Pkcs12LoaderLimits limits = new Pkcs12LoaderLimits()
{
    PreserveStorageProvider = true // true => seeing access denied; false => works
};

X509CertificateLoader.LoadPkcs12(File.ReadAllBytes("cert.pfx"), "1234", loaderLimits: limits);

which seems inconsistent with what you're describing. I'd be still interested in seeing steps how to create a cert you're describing. We also noticed that for some reason this didn't repro for everyone.

This most likely regressed with: #107005 but it was also fixing another issue so we need to figure out solution which makes this work with both scenarios and most likely your test case as well (and therefore my request to share steps to create your cert). With that PR reverted locally I wasn't able to repro this problem anymore but I've additionally seen some more tests failing locally with Access Denied (but it was less tests failing with this reverted) and that doesn't repro on CI for some reason. Given our main expert in this area @bartonjs is out of office and holidays season approaching I'm not sure if we will be able to make any fix this year but collecting more information and test cases will be very valuable to fix this correctly in the next iteration.

@DierkDroth
Copy link

DierkDroth commented Dec 9, 2024

@krwq additional details:

  • I don't need to apply Pkcs12LoaderLimits to reproduce the issue
  • I get the exception as reported by the OP when not replacing the obsolete code but going with the X509Certificate2.ctor
  • I don't get any exception at all when replacing the obsolete code as per my post. Not even Kestrel throws any exception, it's just not working.
    Please let me know if you needed anything else.

I can't comment on how this regression was introduced to the .NET code, since I'm not part of the .NET9 dev team

@krwq
Copy link
Member

krwq commented Dec 9, 2024

@DierkDroth thanks for clarification - when you say it doesn't work on Windows does Kestrel log look normal as if it started correctly but it doesn't let you connect?

How did you create a certificate a pfx/PKCS12 you're passing in?

@DierkDroth
Copy link

@krwq sorry I'm neither a Kestrel expert nor a certificate expert. I did not notice any Kestrel errors nor logs in VS. The certificate is a PFX format certificate which I loaded as embedded resource to a C# byte array (not sure why that would be relevant though...).

@krwq
Copy link
Member

krwq commented Dec 9, 2024

@DierkDroth pfx can be created in multiple ways and format has some slight variations between implementations. Knowing how you created it (i.e. command line) will tell us more what we need to fix.

@DierkDroth
Copy link

@krwq I purchased the PFX from a certificate provider. Unfortunately I don't recall the details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants