I'm trying to set a Certificate for identityserver and it keeps failing with a "no access to private key error".
Taking it out of identityserver, the following code throws an access denied error
static X509Certificate2 GetCertificateFromDisk()
{
using (var stream = File.Open(#"patht-to-pfx", FileMode.Open))
{
var cert = new X509Certificate2(ReadStream(stream), "password", X509KeyStorageFlags.MachineKeySet);
return cert;
}
}
When running the code as administrator it works fine, not when running it under my own account. Eventually I want to run it as localsystem.
I even added 'Everyone' under the certificates private key permissions in my local computer certificate store,
screenprint here
... still I get the exception.
What is wrong here? Going Crazy about it
Update
Great tips from CryptoGuy in the answer below. Important note: Opening the file is not correct only Identityserver3 still failed when getting the certificate from the store. What made it work was to regenerate the certificate using Keith Sparkjoy's tool SerfCert. My previous certificate was generated using powershell. So keep in mind that powershell certificates have issues with accessibility of private key. Thanks to Keith for the tool!
There are few things to consider.
1) you are performing write access to Local Machine store. X509KeyStorageFlags.MachineKeySet attempts to save private key to Local Machine store. Therefore, you need administrator permissions to write there. You should remove this flag to perform read-only access
2)
Documentation says that adding permissions in MMC (manage private key-option on a certificate) should allow this, but it doesn't seem to work
it works on an already saved private keys.
What you really should do is to import certificate and private key to Local Machine store and then configure your application to reference installed certificate.
3) if your application runs under unpriveleged account and the key don't need to be shared, then you should use Current User store.
Related
I'm working with X509 certificates and have a MyCert.pfx file that contains the certificate and both public and private keys. It happens that I exported this certificate from a certificate store on my local machine.
My goal is to pretend I'm on a different machine and read the PFX file and make a new X509Certificate2 from the data and password that I have.
I can do that successfully on my own machine as long as I add the UserKeySet flag to the constructor call.
var flags = X509KeyStorageFlags.UserKeySet;
var cert = new X509Certificate2(certKeyData, certPwd, flags);
What bothers me is that my constructor call fails ("Access denied.") without the UserKeySet flag. I know I need the flag to point to my local (personal) certificates in the machine store, but the real question is why the constructor is looking into my personal or machine key stores at all. I'm trying to pretend I'm on a different machine that has no such store.
Q. Should I be able to create an X509Certificate2 WITHOUT looking in a store on my local machine? If not, why not? Isn't the certificate just a pile of bytes that is unrelated to any key store on any particular machine? Can they exist without reference to, or accessing, a local store? Thank you.
I am attempting to load a certificate with private key from a pfx file and import it to the LocalMachine/My (Personal) certificate store. My code works fine except that when I view the certificate in the store it says
"The associated private key cannot be found"
and further, certutil says
"Cannot find the certificate and private key for decryption"
The strange part is that my code works fine on Windows 7 development box but not on Windows Server 2008 R2 or 2012. Also strange that if I manually import the pfx file using mmc, the private key seems to persist properly.
Here is the code I am using to load the file and import :
// load the certificate from pfx file
X509Certificate2 cert = new X509Certificate2(filePath, pfxPassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
// import to the store
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite); //tried MaxAllowed as well
store.Add(caCert);
store.Close();
Any ideas? For background info, I am also generating the certificate in code at an earlier step using BouncyCastle. I ran into some problems persisting the private key during that step but was solved with the answer from this question. Also the code that is attempting the import is running as administrator.
A little time away from this problem helped me refine my investigation. I tracked down the private key file for the imported certificate in C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
and found that the file had no owner and no permissions set (not even for Administrators or System). Modifying these permissions manually caused the "associated private key" message to go away when viewing the cert in the store.
That led me to modify my code to set permissions on the private key before attempting to import it into the store :
https://stackoverflow.com/a/4902009/332610
hooray!
I'm trying to digitally sign a PDF document using Syncfusion PDF 10.4, like so:
PdfLoadedDocument document = new PdfLoadedDocument(inputStream);
PdfCertificate certificate = PdfCertificate.FindBySubject(certificateStoreType, certificateSubjectName);
PdfSignature signature = new PdfSignature(document, document.Pages[0], certificate, "Signatur");
signature.Bounds = new RectangleF(new PointF(5, 5), new SizeF(100, 100));
This works great for my local user account after installing a suitable certificate using MMC (adding the Certificates snap-in for My user account and storing it in Personal), but not for a service (choosing Service account this time, and picking my service). Running the same code results in no suitable certificate being found, i.e. certificate is null. Furthermore, PdfCertificate.GetCertificates() throws an AccessViolationException, which I assume is a bug on Syncfusion's end.
I can, however, reproduce the same problem without Syncfusion code:
var store = new System.Security.Cryptography.X509Certificates.X509Store("My");
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
foreach (var item in store.Certificates)
{
…
}
Run as my own user, the certificate shows up (as do all the others shown in MMC under Personal), but if I debug the service (by running it, then invoking System.Diagnostics.Debugger.Launch()), I only get a "CN=LOCAL SERVICE" certificate, which doesn't show up in MMC at all.
I'm assuming that I need to A) tell it to open the correct certificate store, or B) change something about the way the service is installed or run, such as giving it a different identity, enabling UserInteraction, etc. Currently, it runs using LocalService and with UserInteraction disabled.
From what I remember, Windows machine accounts (like LocalService) use the machine certificate store. This means that in your code, you have to access the store with StoreLocation.LocalMachine.
var store =
new System.Security.Cryptography.X509Certificates.X509Store(StoreLocation.LocalMachine);
Note that if you decide to run the service under specific identity, you should rather first login as the identity, then import the certificate to the Personal store and then, use StoreLocation.CurrentUser.
The answer appears to be that .NET doesn't support accessing service account certificate stores without P/Invoke or the like:
I don't think that any of the .NET APIs allow access to the Services Certificate store.
However, you can install the certificate into the CurrentUser store of the account that the service runs under.
I've changed the service to run under its own user (which doesn't need admin rights), ran mmc.exe as that user using runas, and imported the certificate to that user's personal store.
I ran into this problem, and to solve it had to allow the "Local Service" account to access the "Local Computer" certificate store using the tool "WinHttpCertCfg"
It is described in detail here:
https://support.microsoft.com/en-us/help/901183/how-to-call-a-web-service-by-using-a-client-certificate-for-authentication-in-an-asp-net-web-application
We have two environments that should be identical but one of them raises an error when we try to generate a SAML message signature. I haven't looked at SAML before and I am not exactly sure what it tries to do
Part of the code:
X509Certificate2 x509Certificate = (X509Certificate2)Application[ASP.global_asax.IdPX509Certificate];
try
{
SAMLMessageSignature.Generate(samlResponse, x509Certificate.PrivateKey, x509Certificate);
}
catch (Exception ex)
{
app = File.AppendText(#"C:\SAML.txt");
app.WriteLine(ex.Message.ToString());
app.Flush();
app.Close();
}
The exception message is
Keyset does not exist
Does anyone have any idea of what I should be looking at?
Thanks in advance.
Hi please check the following on your setup.
Set the correct access control entries, ACLs, to the certificate you installed.
Add Modify access role for NETWORK SERVICE to the certificate.
If you are using Windows 2008 and Windows 7, you can access the private key from the certificate
snap-in in the MMC.
If it still did not work, add Modify access role also for IIS_IUSRS.
Hope it will help you.
Thank you!
Check to see if the certificate stored in the HttpApplicationState object's key ASP.global_asax.IdPX509Certificate was loaded successfully. If the certificate is being loaded from a PFX file, ensure that it is present on the disk and accessible by the account your web app is running under. If the certificate is being loaded from a certificate store, ensure that it is installed in the correct store and that the account your web app is running under can access the certificate.
You can use winhttpcertcfg.exe to install certificates into system keystores and manage certificate ACLs. The KB article http://support.microsoft.com/kb/901183 contains some additional info.
I have an ASP.NET web service which is receiving a byte array representing the contents of a .pfx file containing an X.509 certificate. The server-side code is using the System.Security.Cryptography.X509Certificate2 constructor to load the certificate from the bytes:
X509Certificate2 native_cert = new X509Certificate2(
pkcs12_buf /*byte array*/,
password,
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable
);
Depending on who my service process is running as, this call will either succeed, or fail with an "internal error" exception. The last call on the exception stack is to X509Utils._LoadCertFromBlob, which is unmanaged code in mscore.dll.
This code succeeds when run from a console application in an interactive login using the service account's credentials. It fails when running under w3wp.exe in an application pool that uses the service account's credentials. Changing the app pool identity to an administrator fixes the problem, so it must be a privilege issue, but I have no idea what privilege could be necessary for this. The code does not touch either the filesystem or the Windows certificate stores.
[UPDATE: More Info]
This error appears in the Windows Event Log:
*Cryptographic Parameters:*
**Provider Name:** Microsoft Software Key Storage Provider
**Algorithm Name:** Not Available.
**Key Name:** {E182E13B-166D-472A-A24A-CBEF0808E9ED}
**Key Type:** User key.
*Cryptographic Operation:*
**Operation:** Open Key.
**Return Code:** 0x2
Any ideas?
I just found the solution to this one myself:
X509KeyStorageFlags flags = X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet;
X509Certificate2 cert = new X509Certificate2(pkcs12_buf, password, flags);
The trick here is to use the local key store MachineKeySet flag instead of the user profile key store, which is the default if you don't specify an alternative location. Because the ASP.NET process identity doesn't load the user profile store, you can't access the store when importing a certificate programmatically, but you can access the machine store.
I think PersistKeySet just keeps the private key loaded, but I'm not sure exactly what it does - it's required if you need to access the private key for some reason though.
Try granting the ASP.NET account permissions to the following folder: C:\Documents And Settings\All Users\Microsoft\Crypto\RSA\MachineKeys\ (may vary according to your environment)