I'm migrating a tool that creates Certificate Enrollment Request (certmgr.msc) that prompts a security dialog to assign it a password, then send that request to the CA and later the CA sends back a Base 64 encoded certificate. Everything is fine.
Now, that i have that b64string, i can convert it to a certificate using
var bytes = Encoding.UTF8.GetBytes(b64string);
var certificate = new X509Certificate2(bytes);
the thing is that i need to install that certificate in CurrentUser/Personal store to sign transactions, but i can't because the private key is not within the installed certificate.
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();
I think i must set the password withing the X509Certificate2 constructor, but how could i get that password? Or how could i pair the certificate request and the installed certificate?
I have some old C code that uses XEnroll i think, that does what i want in 1 line:
hr = m_pXEnroll->raw_acceptPKCS7( PKCS7 );
What i'm doing wrong? Maybe my focus is incorrect
I made this up using CertEnrollLib.
As #Crypt32 pointed, it is just as easy as IX509Enrollment.InstallResponse(...)
This is my code:
CX509Enrollment objEnroll = new CX509EnrollmentClass();
objEnroll.Initialize(X509CertificateEnrollmentContext.ContextUser);
objEnroll.InstallResponse(InstallResponseRestrictionFlags.AllowNone, pkcs7, EncodingType.XCN_CRYPT_STRING_BASE64, null);
In my case, for this code to work i have to have a Certificate Enrollment Request, that i generated using the same lib. I'll post the link only cause it's not directly related to this topic.
https://www.sysadmins.lv/retired-msft-blogs/alejacma/how-to-create-a-certificate-request-with-certenroll-and-net-csharp.aspx
I don't know if there is a more pure C# way of doing this in the framework version i'm using (4.0), but this worked for me.
We're doing an integration with Google via RESTful API and I need to sign a payload of a JWT with RSA-SHA256 and all I have is a Private Key as a string, that looks like
-----BEGIN PRIVATE KEY-----
MIIEvgIBfADANBg9qhkdsiG9w0BAQEFAASCBKgw
......
-----END PRIVATE KEY-----
I've been looking everywhere for a solution, but everyone's talking about X509Certificate2 which needs a p12 file, or some Certificates. Now I don't have either of those, I only have a string that is the private key.
Google recommends https://jwt.io/ and it works with the key string, but well, I need my CODE to do it. There are 3 libraries listed in the page:
One of them belongs to Microsoft and has absolutely no documentation.
Another one is using X509Certificate2 or specifically for string keys only has a link to this place http://www.donaldsbaconbytes.com/2016/08/create-jwt-with-a-private-rsa-key/ which uses some Certificate files I don't have, making it a wrong and unhelpful link to begin with.
Same creators of #2 have another lib, but it's for phones and it actually has a method for RSA256 signing which takes private key as a string of exactly my format.
So my question is - is there some working solution for my case? Because I can't believe that no one else has integrations with Google.
I know of a way to convert this to a pfx that you can use in C#.
First, install OpenSSL if you haven't already. (You could get the latest "Win64 OpenSSL v#.#.#x Light" from http://slproweb.com/products/Win32OpenSSL.html, though I take no responsibility for this source.)
You may want to add "C:\Program Files\OpenSSL\bin\" to your account's path variable, so that "openssl.exe" can be used from anywhere in the command line.
In a command window, navigate to where your private key file is. Let's call it "priv.key". Issue the following two commands, ignoring the comments:
# Create public self-signed certificate CRT file (with 7000yr validity) from private key (may leave all info empty)
openssl req -x509 -sha256 -new -key priv.pem -out pub.crt -days 2555000
# Combine into PFX container (encrypted with AES-256) (certificate needs to be included for .NET to read successfully)
openssl pkcs12 -export -aes256 -CSP "Microsoft Enhanced RSA and AES Cryptographic Provider" -inkey priv.pem -in pub.crt -out priv.pfx
Note that on the last command, I am creating an encrypted pfx (this is optional - I believe you could replace -aes256 by -nodes to skip it), and I am configuring the cryptographic provider such that the key can be used for SHA256 operations without C# complaining.
You now have a pfx file that you can load using the constructor of X509Certificate2.
I tend to use this cheat sheet for common OpenSSL commands:
https://www.sslshopper.com/article-most-common-openssl-commands.html
I am attempting to create a TCP connection on TLS encryption in C#, using an OpenSSL generated cert.
The SslStream sample code given here seems to work using a cert created with windows makecert.exe, which comes out as a .cer file. It does not work with a cert created through OpenSSL, which is a .pem file, throwing excpetion: "The server mode SSL must use a certificate with the associated private key."
Both cert files are being parsed successfully into X509Certificate objects as I can see their issuers and subjects and other properties, and note that the "HasPrivateKey" property is false "PrivateKey" property is null on both of them.
I found this which says that you need to combine the (OpenSSL) certificate and private key into one PKCS12 package. Yet a PKCS12 package is the file format .pfx -- why does an OpenSSL cert have to be combined with a private key into a pfx, but a makecert-generated .cer file does not need to be a pfx (and is not PKCS12)?
Also, what is different about the OpenSSL certificate in the first place that makes it throw this exception about a missing private key, when the MakeCert certificate also does not have a private key? Or to put another way, why does the MakeCert certificate not seem to require a private key, like the OpenSSL cert?
Someone on IRC suggested to me that it might be that makecert is putting credentials in the windows Certificate Store. I didn't expect that would be the case since we are exporting files, but I moved my SslStream prototype (with makecert certificates) to a different machine (ie not the one where makecert was run) and I got the same error "The server mode SSL must use a certificate with the associated private key."
So officially, the answer is "makecert puts the key into your cert store, and when you run AuthenticateAsClient, in the background it is pulling the private key out of there. This is why the makecert certificate works and the OpenSSL cert doesn't, even though they are almost identical.
Taking it a step further, to get the thing working with OpenSSL certs, I'm sure the advice I linked in the question about combining the public and private keys into a PKCS12 (.pfx) file would have worked, however I wanted to load/combine them on the fly. I found this codeproject article which contains sample code that does all the dirty work of decoding the RSA private key, making it into an RSACryptoProvider, and attaching that object to the X509Certificate2.PrivateKey property. After doing this and providing paths to the seperate cert and private key files generated by OpenSSL, everything works great!
I'm trying to read the private key of a certificate which has been shared with me by a third-party service provider, so I can use it to encrypt some XML before sending it to them over the wire. I'm doing so programmatically in C#, but I think this is a permissions or misconfiguration issue, so I'll focus on the facts which seem to be most relevant:
I don't think this issue is code-related; my code works on other computers, and the issue affects sample code from Microsoft.
The certificate was provided as a PFX file and is just for test purposes, so it also includes a dummy certification authority.
Using MMC.exe, I can import the certificate into the personal store for the local machine, before granting permissions on the private key to all relevant accounts, and dragging and dropping the certification authority into the Trusted Root Certification Authorities.
Using C#, I can load the certificate (identified by its thumbprint) and verify that it has a private key using X509Certificate2.HasPrivateKey. However, trying to read the key causes an error. In .NET a CryptographicException is thrown with the message "Invalid provider type specified" upon trying to access the property X509Certificate2.PrivateKey. In Win32, calling the method CryptAcquireCertificatePrivateKey returns the equivalent HRESULT, NTE_BAD_PROV_TYPE.
This is the same exception which also occurs when using two of Microsoft's own code samples to read the private key of the certificate.
Installing the same certificate in the equivalent store for the current user, instead of the local machine, allows the private key to be successfully loaded.
I'm on Windows 8.1 with local administrator rights, and I've tried running my code in both normal and elevated modes. Colleagues on Windows 7 and Windows 8 have been able to load the key from the local machine store for the same certificate.
I can successfully read the private key of the self-signed IIS test certificate, which is in the same store location.
I am already targeting .NET 4.5 (this error has been reported with some older versions of the framework).
I don't think this is a problem with certificate templates, because I would expect that to affect both the local machine and current-user stores equally?
Unlike my colleagues, I have made multiple previous attempts to uninstall and re-install the certificate in various ways, including via IIS Manager and also including an older certificate from the same issuer. I can't see any traces of old or duplicate certificates in MMC. However, I do have many private key files of identical size which, based on the last-write time, must have been left behind after my various installation attempts. These are found at the following locations, for the local machine and current user stores respectively:
c:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
c:\Users\\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-[rest of user ID]
So, can anyone please advise whether:
It's a good idea to uninstall the certificate using MMC, delete all those files which look like orphaned private keys, and then re-install the certificate and try again?
There any other files which I should try to manually delete?
There's anything else I should try?
UPDATE - Added a code sample showing an attempt to read a private key:
static void Main()
{
// Exception occurs when trying to read the private key after loading certificate from here:
X509Store store = new X509Store("MY", StoreLocation.LocalMachine);
// Exception does not occur if certificate was installed to, and loaded from, here:
//X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection scollection = X509Certificate2UI.SelectFromCollection(fcollection, "Test Certificate Select", "Select a certificate from the following list to get information on that certificate", X509SelectionFlag.MultiSelection);
Console.WriteLine("Number of certificates: {0}{1}", scollection.Count, Environment.NewLine);
foreach (X509Certificate2 x509 in scollection)
{
try
{
Console.WriteLine("Private Key: {0}", x509.HasPrivateKey ? x509.PrivateKey.ToXmlString(false) : "[N/A]");
x509.Reset();
}
catch (CryptographicException ex)
{
Console.WriteLine(ex.Message);
}
}
store.Close();
Console.ReadLine();
}
I had the same problem on Windows 8 and Server 2012/2012 R2 with two new certificates I recently received. On Windows 10, the problem no longer occurs (but that does not help me, as the code manipulating the certificate is used on a server). While the solution of Joe Strommen in principle works, the different private key model would require massive change to the code using the certificates. I find that a better solution is to convert the private key from CNG to RSA, as explained by Remy Blok here.
Remy uses OpenSSL and two older tools to accomplish the private key conversion, we wanted to automate it and developed an OpenSSL-only solution. Given MYCERT.pfx with private key password MYPWD in CNG format, these are the steps to get a new CONVERTED.pfx with private key in RSA format and same password:
Extract public keys, full certificate chain:
OpenSSL pkcs12 -in "MYCERT.pfx" -nokeys -out "MYCERT.cer" -passin "pass:MYPWD"
Extract private key:
OpenSSL pkcs12 -in "MYCERT.pfx" -nocerts -out "MYCERT.pem" -passin "pass:MYPWD" -passout "pass:MYPWD"
Convert private key to RSA format:
OpenSSL rsa -inform PEM -in "MYCERT.pem" -out "MYCERT.rsa" -passin "pass:MYPWD" -passout "pass:MYPWD"
Merge public keys with RSA private key to new PFX:
OpenSSL pkcs12 -export -in "MYCERT.cer" -inkey "MYCERT.rsa" -out "CONVERTED.pfx" -passin "pass:MYPWD" -passout "pass:MYPWD"
If you load the converted pfx or import it in the Windows certificate store instead of the CNG format pfx, the problem goes away and the C# code does not need to change.
One additional gotcha that I encountered when automating this: we use long generated passwords for the private key and the password may contain ". For the OpenSSL command line, " characters inside the password must be escaped as "".
In my case, I was trying to use a self-signed certificate with PowerShell's New-SelfSignedCertificate command. By default, it will generate a certificate using the CNG (Crypto-Next Generation) API instead of the older/classic crypto CAPI. Some older pieces of code will have trouble with this; in my case it was an older version of the IdentityServer STS provider.
By adding this at the end of my New-SelfSignedCertificate command, I got past the issue:
-KeySpec KeyExchange
Reference on the switch for the powershell command:
https://learn.microsoft.com/en-us/powershell/module/pkiclient/new-selfsignedcertificate?view=win10-ps
Here is another reason that this can happen,
this was a weird issue and after struggling for a day I solved the issue.
As an experiment I changed permission for "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys" folder which holds private key data for certificates using Machine key store. When you change permission for this folder all privatekeys shows up as "Microsoft Software KSP provider" which is not the provider (in my case they are supposed to be " Microsoft RSA Schannel Cryptographic Provider").
Solution: Reset permissions to Machinekeys folder
Original permission for this folder can be found in here. In my case I have changed permission for "Everyone", gave read permissions where it removed "Special permissions" tick. So I checked with one of my team member (Right click folder> Properties > Security > Advanced > select "Everyone" > Edit > Click "Advanced settings" in permission check box list
Hope this will save someone's day!
Here is where I found the answer source, credit goes to him for documenting this.
In my case, the following code worked fine in localhost (both NET 3.5 and NET 4.7):
var certificate = new X509Certificate2(certificateBytes, password);
string xml = "....";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
xmlDocument.LoadXml(xml);
SignedXml signedXml = new SignedXml(xmlDocument);
signedXml.SigningKey = certificate.PrivateKey;
//etc...
But it failed when deployed to an Azure Web App, at certificate.PrivateKey
It worked by changing the code as follows:
var certificate = new X509Certificate2(certificateBytes, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
//^ Here
string xml = "....";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
xmlDocument.LoadXml(xml);
SignedXml signedXml = new SignedXml(xmlDocument);
signedXml.SigningKey = certificate.GetRSAPrivateKey();
// ^ Here too
//etc...
A whole day of work lost thanks to Microsoft Azure, once again in my life.
The link to Alejandro's blog is key.
I believe this is because the certificate is stored on your machine with the CNG ("Crypto Next-Generation") API. The old .NET API is not compatible with it, so it doesn't work.
You can use the Security.Cryptography wrapper for this API (available on Codeplex). This adds extension methods to X509Certificate/X509Certificate2, so your code will look something like:
using Security.Cryptography.X509Certificates; // Get extension methods
X509Certificate cert; // Populate from somewhere else...
if (cert.HasCngKey())
{
var privateKey = cert.GetCngPrivateKey();
}
else
{
var privateKey = cert.PrivateKey;
}
Unfortunately the object model for CNG private keys is quite a bit different. I'm not sure if you can export them to XML like in your original code sample...in my case I just needed to sign some data with the private key.
What worked for me:
IIS / Application pool / Load User Profile = true
As many other answers have pointed out, this issue arises when the private key is a Windows Cryptography: Next Generation (CNG) key instead of a "classic" Windows Cryptographic API (CAPI) key.
Beginning with .NET Framework 4.6 the private key (assuming it's an RSA key) can be accessed via an extension method on X509Certificate2: cert.GetRSAPrivateKey().
When the private key is held by CNG the GetRSAPrivateKey extension method will return an RSACng object (new to the framework in 4.6). Because CNG has a pass-through to read older CAPI software keys, GetRSAPrivateKey will usually return an RSACng even for a CAPI key; but if CNG can't load it (e.g. it's an HSM key with no CNG driver) then GetRSAPrivateKey will return an RSACryptoServiceProvider.
Note that the return type for GetRSAPrivateKey is RSA. Beginning with .NET Framework v4.6 you shouldn't need to cast beyond RSA for standard operations; the only reason to use RSACng or RSACryptoServiceProvider is when you need to interop with programs or libraries that use the NCRYPT_KEY_HANDLE or the key identifier (or opening a persisted key by name). (.NET Framework v4.6 had a lot of places that still cast the input object to RSACryptoServiceProvider, but those were all eliminated by 4.6.2 (of course, that's more than 2 years ago at this point)).
ECDSA certificate support was added in 4.6.1 via a GetECDsaPrivateKey extension method, and DSA was upgraded in 4.6.2 via GetDSAPrivateKey.
On .NET Core the return value from Get[Algorithm]PrivateKey changes depending on the OS. For RSA it's RSACng/RSACryptoServiceProvider on Windows, RSAOpenSsl on Linux (or any UNIX-like OS except macOS), and a non-public type on macOS (meaning you can't cast it beyond RSA).
Using Visual Studio 2019 and IISExpress, I was able to correct this problem by removing the following flag when loading the .pfx|.p12 file:
X509KeyStorageFlags.MachineKeySet
Before:
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable
After:
X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable
Normally, I'll load the cert this way:
var myCert = new X509Certificate2("mykey.pfx", "mypassword", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
This does NOT raise an Exception, instead the Exception is raised when attempting to use the certificate (or in my case, when trying to obtain the .PrivateKey). I've found this issue can be caused when the invoking user has insufficient permissions.
Since I rely on the MachineKeySet flag for some environments, my current solution is to swallow the Exception, change the flags, try again. :/
A more organic solution would be to test the permissions level and set this flag dynamically, however I'm not aware of a simple way to do this, hence the fallback.
NOTE: The .pfx file I'm using was created from a website that uses a JavaScript library (digitalbazaar/forge) which does NOT use CNG (Cryptography Next Generation) Key Storage Providers. here are many common causes for this same error (the most common fixes related to CNG extensions, which have -- unfortunately even changed namespaces in .NET versions), which throw the same error. Microsoft should ultimately be more verbose when throwing these types of errors.
I also had this issue and after attempting the suggestions in this post without success. I was able to resolve my issue by reloading the certificate with the Digicert certificate utility https://www.digicert.com/util/. This allows one to select the provider to load the certificate into. In my case loading the certificate into the Microsoft RSA Schannel Cryptographic Provider provider where I had expected it to be in the first place resolved the issue.
Powershell version of the answer from #berend-engelbrecht, assuming openssl installed via chocolatey
function Fix-Certificates($certPasswordPlain)
{
$certs = Get-ChildItem -path "*.pfx" -Exclude "*.converted.pfx"
$certs | ForEach-Object{
$certFile = $_
$shortName = [io.path]::GetFileNameWithoutExtension($certFile.Name)
Write-Host "Importing $shortName"
$finalPfx = "$shortName.converted.pfx"
Set-Alias openssl "C:\Program Files\OpenSSL\bin\openssl.exe"
# Extract public key
OpenSSL pkcs12 -in $certFile.Fullname -nokeys -out "$shortName.cer" -passin "pass:$certPasswordPlain"
# Extract private key
OpenSSL pkcs12 -in $certFile.Fullname -nocerts -out "$shortName.pem" -passin "pass:$certPasswordPlain" -passout "pass:$certPasswordPlain"
# Convert private key to RSA format
OpenSSL rsa -inform PEM -in "$shortName.pem" -out "$shortName.rsa" -passin "pass:$certPasswordPlain" -passout "pass:$certPasswordPlain" 2>$null
# Merge public keys with RSA private key to new PFX
OpenSSL pkcs12 -export -in "$shortName.cer" -inkey "$shortName.rsa" -out $finalPfx -passin "pass:$certPasswordPlain" -passout "pass:$certPasswordPlain"
# Clean up
Remove-Item "$shortName.pem"
Remove-Item "$shortName.cer"
Remove-Item "$shortName.rsa"
Write-Host "$finalPfx created"
}
}
# Execute in cert folder
Fix-Certificates password
I faced the same problem in our IIS app:
System.Security.Cryptography.Pkcs.PkcsUtils.CreateSignerEncodeInfo(CmsSigner signer, Boolean silent)
System.Security.Cryptography.Pkcs.SignedCms.Sign(CmsSigner signer, Boolean silent)
System.Security.Cryptography.Pkcs.SignedCms.ComputeSignature(CmsSigner signer, Boolean silent)
Regenerating certs as mentioned here didnt help.
I also noticed that test console app works fine under pool user.
Problem disappeared after clearing "Enable 32-bit Applications" setting for IIS app pool.
I tried everything in this post, but for me the solution was:
Import the original .p12 file into my local machine
Export it as a .pfx file checking the "Export all extended properties" and "Include all the certificates in the certification path if its possible" options
Read the new certificate using this flag options from this post solution:
var certificate = new X509Certificate2(certKeyFilePath, passCode,
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet );
For a .net 4.8 WCF service I was getting this error because i hadn't (also) set the httpRuntime version.
Without the httpRuntime set i was getting the error whenever a secured .net tcp binding was present.
<system.web>
<compilation targetFramework="4.8" />
<httpRuntime targetFramework="4.8" />
<!--<customErrors mode="Off" />-->
</system.web>
I had already setup the required permissions in mmc.exe -> add snap-in -> certificates -> personal -> all tasks -> manage private keys -> add [computer name]\IIS_IUSRS (all my application pools are ApplicationPoolIdentity [default] - which is covered by IIS_IUSRS)
the PrivateKey and PublicKey properties are outdated beginning with NET 4.6. Please use:
cert.GetRSAPrivateKey() or GetECDsaPrivateKey()
cert.GetRSAPublicKey() or GetECDsaPublicKey()
Regards
After following the accepted answer (specifying KeySpec), the exception changed to System.Security.Cryptography.CryptographicException: Invalid provider type specified.. I resolved that exception by giving my web application access to the private key (IIS_IUSRS). I discovered that this would also fix the problem with my original certificate. So before generating and deploying new certificates, check the private key's permissions as well.
The problem is your code is not able to read the PFX file.
convert the pfx file to RSA format by doing the below steps.
Get the certificate and extract the pfx file from the certificate.
use the password 123456 below to have a quick solution.
rename your pfx to 'my.pfx' file to make it simple and put it in "C:\Certi"
make sure you have open SSL installed already in the system.
open cmd in windows system and type --> OpenSSL
Stay cool and just run these ones by one --> copy paste.
*Note
-passin is your Pfx file password
-passout is the new password for converted pfx.
1. pkcs12 -in "C:\Certi\my.pfx" -nokeys -out "C:\Certi\MYCERT.cer" -passin "pass:123456"
2. pkcs12 -in "C:\Certi\my.pfx" -nocerts –out “C:\Certi\MYCERT.pem" -passin "pass:123456" -passout "pass:123456"
3. rsa -inform PEM -in "C:\Certi\MYCERT.pem" -out "C:\Certi\MYCERT.rsa" -passin "pass:123456" -passout "pass:123456"
if you face issue in the 3rd command go here https://decoder.link/converter
Click PKC#12 To PEM
upload your pfx file and get it converted online.
download the zip file.
it contains 3 files. just copy ".key" file and rename it as my.key and put in "C:\Certi"
4. rsa -in C:\Certi\my.key -out C:\Certi\domain-rsa.key
5. pkcs12 -export -in "C:\Certi\MYCERT.cer" -inkey "C:\Certi\domain-rsa.key" -out "C:\Certi\CONVERTED.pfx" -passin "pass:123456" -passout "pass:123456"
**Also, you can try below things if the issue still persists**
Given access to app pool or IIS user to folder "mandatory to do"
Path --- > C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
Delete the old keys (clear up the mess)
Path --- > C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
This error went away after i removed the certificate from the store and imported it again from the .pfx file, using the Certificate Import Wizard (double-click the .pfx file) and an extra import option.
After checking the import option (same step where password is entered):
"Mark this key as exportable. This will allow you to back up or transport your keys at a later time."
The privatekey could now be accessed from code without any errors.
I also explicitly select the "Personal" store on the 2nd to last step, but I don't think this matters.
It seems on Windows 10, if I run my program without administrative privileges (whether I use the PrivateKey property or the GetRSAPrivateKey() extension method), I will see this exception (see the title of this discussion thread for the exception). If I run my program with administrative privileges and use the PrivateKey property, I will also see this exception. Only if I run my program with administrative privileges and use the GetRSAPrivateKey() extension method, I will not see this exception.
I also had this issue, I changed the '.jks' to '.pfx' without typing the password, once I changed the key store type again with the password it is worked successfully.
After experiencing this issue on some computers in a security-critical environment, I found that, contrary to several answers, updating the Cryptographic Service Provider (CSP) of the certificate from the old CAPI standard to the new CNG standard resolved this issue.
The security policies probably restricted the use of CSPs relying on deprecated cryptographic algorithms.
Updating the CSP to Microsoft Software Key Storage Provider based on these instructions fixed the issues.
I had a very strange issue regarding an imported PFX from OpenSSL on a Linux System and the ADWS (Active Directory Web Service).
When using the Import Certificate GUI through the MMC Snap Ins, the certificate was imported successfully and ADWS could find it and load.
When using this command with Powershell, the certificate appeared to have been imported successfully but ADWS was giving an Event ID 1402 error.
Import-PfxCertificate -FilePath C:\Users\Administrator\Desktop\dc01.test.pfx `
-CertStoreLocation 'Cert:\LocalMachine\My' -Password (ConvertTo-SecureString 'Password123!' -AsPlainText -Force)
Active Directory Web Services was unable to process the server certificate. A certificate is required to use SSL/TLS connections. To use SSL/TLS connections, verify that a valid server authentication certificate from a trusted Certificate Authority (CA) is installed on the machine.
Enabling the debugging this was the culprit:
ADWSHostFactory: [04/01/2023 21:55:59] [6] ProvisionCertificate: caught a CryptographicException: System.Security.Cryptography.CryptographicException: Invalid provider type specified.
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at Microsoft.ActiveDirectory.WebServices.ADWSHostFactory.ProvisionCertificate(ServiceHost host)
I was stumped and tried some of the other solutions here but nothing worked.
Fortunately I discovered this guide from Component Space (https://www.componentspace.com/Forums/1578/SHA256-and-Converting-the-Cryptographic-Service-Provider-Type) which mentions the Cryptographic Provider being the issue as do a lot of others on this issue.
I could not see a way of changing this with powershell, but you can do this with certutil.
certutil.exe -p 'Password123!' -csp "Microsoft Enhanced RSA and AES Cryptographic Provider" -importPFX C:\Users\Administrator\Desktop\dc01.test.pfx
The certificate now works as if I had added it via the GUI.
What I can't understand is why Powershell is adding it with a different cryptographic provider than if I add it through the MMC GUI. I hope this helps some one else with a really weird and annoying bug.