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
WindowsCryptographicException when using symlink as X509Certificate source #27826
Comments
It's not a .NET (Framework or Core) issue, it's a Windows issue (as you surmised, we get an error out of CryptQueryObject).
There are currently no plans to address it, no. There's an amount of guesswork in recovery, which isn't clear that we would want in all cases. @natemcmaster Would it make sense for Kestrel's "cert from file" path to do something like try
{
return new X509Certificate2(path);
}
catch (CryptographicException)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
try
{
if ((File.GetAttributes(path) & FileSystemAttributes.ReparsePoint) != 0)
{
byte[] data = File.ReadAllBytes(path);
return new X509Certificate2(data);
}
}
catch
{
}
}
throw;
} The difference in Kestrel's code from the cert PAL is you know that someone's doing it as part of process startup, and no "wait, are you trying to trick me?" questions really arise. |
Oh bad docker, naughty docker. Yea, seems ok though. |
It's plausible, though it seems like it belongs in a lower level than Kestrel. |
@Tratcher My thinking for putting it in Kestrel is that you have the context to know that this is app startup; so there's probably no trickery around "ooh, I can get you to File.ReadAllBytes a 1.999GB file". I can't come up with a sane restriction (off the top of my head) for making that as a "generically, at any point in a runtime operation" change in our layer. At the Windows layer they wouldn't need the intermediate copy, since they can still just pull from the file descriptor. So both above us (with context) and below us (due to a different access model) can do this sensibly, but it's hard for my layer. |
I can understand you don't want to change the default behavior but there's room for an intermediate API like |
Or a flag on load from file, "FollowSymLinks"? |
For people stuck on this issue (maybe I'm not alone trying to do this?), here is a workaround : |
Another workaround is doing a copy at startup. # The copy is done, because wildcard_certificate.pfx is put into the container using docker secrets, which makes it a symlink.
# Reading a certificate as a symlink is not supported at this moment: https://stackoverflow.com/q/43955181/1608705
# After doing a copy, the copied version is not a symlink anymore.
ENTRYPOINT (IF EXIST "c:\certificates\wildcard_certificate.pfx" (copy c:\certificates\wildcard_certificate.pfx c:\app\wildcard_certificate.pfx)) && dotnet webapplication.dll My application runs in the "c:\app" folder and I put my "to be copied" certificates in "c:\certificates". At startup the certificate is copied to "c:\app", which my environment variables point to. version: "3.7"
services:
webapplication:
image: ({CONTAINER_REGISTRY})/webapplication:({LABEL})
environment:
- ASPNETCORE_URLS=https://+;http://+
- ASPNETCORE_HTTPS_PORT=443
- ASPNETCORE_Kestrel__Certificates__Default__Path=wildcard_certificate.pfx
secrets:
- source: config_secrets
target: C:/app/appsettings.json
- source: wildcard_certificate_pfx
target: c:\certificates\wildcard_certificate.pfx |
Hit this in prod. Bug in Windows. It seems the only possible way of getting the Windows Crypto teams to address their bugs is to actually be willing to switch to OpenSSL if they don't. |
@jhudsoncedaron would it be possible for you to modify the code to read the contents of the file into a using var cert = new X509Certificate2(File.ReadAllBytes(file)); Or is this happening in a higher level, or otherwise unmodifiable, API for you? |
@vcsjones : Haven't you had the crashes resulting from reading the private key into a byte[] leak disk yet? We have. That writes a temp file in native code and maps it. The temp file survives if the process crashes. Also, %TEMP% may be unwritable on site. Setting Epheremal key stops it from writing to disk, but that too is busted due to a different bug in the Windows Crypto API. |
Apologies. |
You should be able to use |
Hi there!
I'd like to use a symlink for constructing my X509Certificate. Currently I'm encoutering a
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Unspecified error
with the following code :
I know that this issue is already known (although I can't find the issue in this repo) as @bartonjs which seems to be responsible of the System.Security area already replied about it on stackoverflow (see here)
The work around suggested work BUT let me show you a use case that become much more complicated :
When working with AspNet Core using Kestrel in a Windows container orchestrated by Docker Swarm, I would love to use secrets for my SSL certificates (SSL Offloading on a proxy is not an option in my case). Unfortunately, Docker secrets are symbolic links. Therefore, to make it work I have to go from just declaring the secret and an environment variable (Kestrel__Certificates__Default__Path) to tuning Kestrel and load manually the certificate.
Do you plan to fix this ? My guess is, that's coming from CryptQueryObject in crypt32.
Just in case it's needed :
and
The text was updated successfully, but these errors were encountered: