ADFS Export Default Token Signing Certificate Private Key - certificate

How can I export the Token Signing Certificate that is created when ADFS 3.0 is installed? When I open up the certificate MMC, I am able to see the certificate however the message 'You have a private key that corresponds to this certificate' is missing and I am unable to export the private key. I read in the article ADFS deep dive: Certificate Planning that I can find it in Active Directory in the following container:
CN=ADFS,CN=Microsoft,CN=Program Data,DC=domain,DC=com
However, although I can get to that container, all I see is a GUID inside and do not know how to export the private key out of Active Directory.
How can I get the private key?
******************************************** EDIT ********************************************
In case anyone comes to this later, the certs are actually in the personal cert store of the ADFS service account but they are NOT exportable. You almost certainly want the SSL cert private key NOT the token signing cert private key. The documentation
I was following to set up ADFS for SharePoint was a little confusing. The private key had to exported for the SSL cert, however the thumbprint of the token signing cert had to be placed in the web config. I was incorrectly trying to export the private key of the token signing cert.
******************************************** EDIT ********************************************

You mean the self-signed ones you get with automatic rollover?
If so, where do you see these with mmc?
They are stored in a combination of an AD container and the ADFS DB.
So you can't export in the normal manner.
For a very good reason - security. If you have the private key you can send / hack anything and it will be accepted as coming from ADFS.
The public key is available in the metadata.
If you have to do this, turn off automatic rollover and use your own certificates.

Related

Is Self-Signed IdentityServer4 signing credential good enough in production?

We are using IdentityServer4 and our version loads the signing key from a PFX file in file system or from the windows certificate store. Using the certificate works. The question is - which certificate issuer should be used in production?
Is a certificate from a public CA recommended? Or is it enough to have a self-signed certificate (without a CA at all) such as it can be created with IIS Manager?
In our tests we have found that the client could still validate the signature in the access token, even if the signing certificate would not have a valid CA chain on the client.
In the docs, it says that you can also use raw key material instead of a certificate:
http://docs.identityserver.io/en/latest/topics/crypto.html#token-signing-and-validation
In this scenario there would be no CA chain whatsoever.
That leads me to the assumption, that when the client loads the public signing key (via the HTTP(s) endpoint), the CA chain information might not be passed anyways. Is that right? Through the loading mechanism via HTTPs you also have a combined security mechanism.
So my conclusion is that for the signing credential a self-signed cert is just as safe as one from VeriSign. Can this be confirmed?
There is no certificate involved in signing and verifying the tokens. Only a private and public key (RSA or ECDSA key).
However a certificate can be useful to "import/transport" the keys into .NET. So, because of that we don't care about who issued the certificate.
When importing the key, one approach is to bundle the certificate that holds the public key + the private key and store it in a PKCE#12 file (.pfx/.p12 extension). Then load that file into .NET. Before .NET 5 working with keys was a bit hard.
The more important thing is that you can manage and deploy the private key in a secure way and that it is persisted over time.
Optionally, you can add support for key-rotation.

keyset does not exist when the private key clearly exists

We have a service that will generate a CA cert and use that CA cert to sign all other required certs on startup.
The CA cert has an associated private key and is stored in the windows certificate store with Exportable flag. This works fine on most machines but on one of our QA's machine we run into some nasty issues.
When I load the CA cert from the cert store in code and checked HasPrivateKey flag it returns true. Then when I attempt to use the CA cert to sign another cert. It throws keyset does not exist exception.
In the certificate store it says the certificate is valid. On the general page it says
You have a private key that corresponds to this certificate
Good sign! But when we try to right click -> Task -> Export it. The include private key button is grayed out and says
The associated private key cannot be found. Only the certificate can
be exported
We thought its a permission issue so we run mmc in admin mode and still the same result.
On my dev machine I noticed that the private key file is stored in %APPDATA%\Microsoft\Crypto\Keys but its not the case for our QA's machine. We cannot find the private key file in the same folder with the timestamp = CA cert generated time. We also looked into
%ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\SystemKeys
%WINDIR%\ServiceProfiles\LocalService
%ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\Keys
but no luck still.
The account used to run the service is Local System so permission shouldnt be an issue here. No special anti-virus installed other than Windows Defender and nothing in Defender's history either.

Problem with ENGINE_load_private_key and PKCS#11

Being stuck with signing (Authenticode) using PKCS#11 tokens, and given the amazingly poor driver support from the vendor (SafeNet), we're signing Windows code on Linux.
All of this is working fine using all of our tokens on several build servers. However, I have one token that fails, depending on the mechanism being used. From Java, using Jsign and the SunPKCS11 provider, everything works fine with this token.
However, from osslsigncode, signing fails with this token:
Unable to enumerate certificates
PKCS11_get_private_key returned NULL
Failed to load private key 9df65894eb084ba3140555614123992:error:26096080:engine routines:ENGINE_load_private_key:failed loading private key:eng_pkey.c:124:
Failed
The difference between the working token and the non-working token is that the non-working token includes not just the certificate, but also its trust chain:
# pkcs11-tool --module libeToken.so --list-objects
Using slot 0 with a present token (0x0)
Certificate Object, type = X.509 cert
label: te-69f298db-2f32-4a94-82ea-3e11829b26cd
ID: 9df65894eb084ba3
Certificate Object, type = X.509 cert
label:
Certificate Object, type = X.509 cert
label:
Using p11tool, the two empty-looking certs above show as:
Type: X.509 Certificate
Label:
Flags: CKA_CERTIFICATE_CATEGORY=CA;
ID:
My other tokens, all of which work fine, do not include these CA certs. This token was created recently, so it may be that either the token firmware is different from my others, or the token installation process has changed since I created the other, working tokens. The certificate is the same on all of them, working and non-working.
I've confirmed (via gdb) that the correct key ID is being passed into ENGINE_load_private_key.
I'm not sure who owns the ENGINE API in this case - is it a token driver issue? (SafeNet) Is it a problem with OpenSC? etc. It would be helpful to find some other tool that uses the API in the same way so I could confirm whether the problem somehow lies with osslsigncode (which isn't actively supported) or one of the lower layers in this tower of cards.
P.S. I used PKCS#11 Spy, and it shows enumeration of all of the certs in the chain, so it's finding the key pair (by ID), but then fails - no errors in PKCS#11 Spy - all CKR_OK.
P.P.S. To address the question of whether this token also has a private key...
Using slot 0 with a present token (0x0)
Logging in to "Code Signing Token 11".
Please enter User PIN:
Private Key Object; RSA
label:
ID: 9df65894eb084ba3
Usage: decrypt, sign, unwrap
Certificate Object, type = X.509 cert
label: te-69f298db-2f32-4a94-82ea-3e11829b26cd
ID: 9df65894eb084ba3
Certificate Object, type = X.509 cert
label:
Certificate Object, type = X.509 cert
label:
The solution, at least for now, seems to be just deleting the CA certs from the token (via SAC Tools on Windows). Once done, osslsigncode (via the PKCS#11 stack) has no problem finding the token. The CA certs aren't needed for signing, so deleting them presents no problem.
It seems that you did NOT login to the token. In pkcs11-tool, use --login --pin <your-pin-code> if you want to retrieve private objects.
It should be noted that the signing process needs an appropriate private key (not certificate).

Azure Service Fabric, KeyVault, SSL Certificates

I want to secure my own HTTPS end point (node.js express.js server) with a certificate which I have deployed to the cluster (that is, it exists in Cert:\LocalMachine\My).
I of course want to avoid having my certificate in source control. I can't use an EndpointBindingPolicy in the ServiceManifest because as far as I'm aware that is just for http.sys(?) based systems, which this isn't.
What I thought is perhaps run a SetupEntryPoint script to:
grab the certificate from the store
export it as a pfx with a random passphrase (or some appropriate format)
copy it to {pkgroot}/certs/ssl_cert.pfx
replace some sort of token in serverinit.js with the random passphrase
This way the server, er, code base doesn't need to have the certificate present, i just needs to trust that it will be there when the service is run.
However I don't think I can do this, if it even is as sensible idea, as the certificates in the store are marked such that the private key is non-exportable! Or, at least, they are with my RDP account!
Is there a way to export the certificate with its private key?
What are my options here?
I ended up writing a powershell script which runs in my release pipeline, arguments are clientID, clientSecret and certificateName. clientSecret is stored as a protected environmental variable for my agent.
Create new application registration under same subscription as KeyVault (which should be same as SF Cluster) (e.g. in portal.azure.com)
Note down app ID
Create app secret
Modify KeyVault ACL with App as principal, set get only on secrets
use REST api with client ID and secret https://learn.microsoft.com/en-us/rest/api/keyvault/getsecret
I chose this over grabbing the certificate in the SetupEntryPoint, for example, as this hides the client secret better from the open world (e.g. developers who shouldn't/don't need access to it)

Loading a server-side certificate *and* a private key from Windows Server cert store?

I'm trying to get this external REST webservice that requires both a server-side certificate and a private key (both of which I got from the publisher as *.pem files of that service).
For my testing, I googled and found a way to combine these two pieces into a *.pfx file - and loading a X509Certificate2 instance from that binary file on disk works just fine.
Now I was trying to put this into the Cert Store on my production Windows Server 2008.
I can get the X509Certificate2 from the cert store in my C# code - no problem:
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySerialNumber, "serial-number-here", false);
if (certs.Count > 0)
{
X509Certificate2 cert = certs[0];
// set the certificate on the RestClient to call my REST service
_restClient.ClientCertificates.Add(cert);
}
store.Close();
But when I do this, then the web service barfs at me, claiming it needs a "SSL certificate"...
Also: when I was loading the X509Certificate2 from disk, from that *.pfx file, I had to provide a password - nothing needs to be provided here, when loading from the cert store.... odd....
It seems that even though I imported the *.pfx which contains both the server-side certificate and our private key, somehow I cannot get both back from the cert store...
Any idea how I can get this to work? Do I need to load the private key from the cert store in a second step? How?
These certificates still remain mainly a big voodoo-like mystery to me ..... can anyone enlighten me?
The first thing to check is to see whether the certificate store does have the private key.
Open up the certificate management snappin and find your certificate, double click it and make sure it has the red highlighted section like in the image below:
Next, if the private key is in the store then maybe the account accessing the certificate does not have permissions on the private key. There are two ways to check this:
In the certificate management snappin, right click the certificate > All tasks > Manage private keys. (You should be able to check and edit permissions here)
In your code you could access the PrivateKey property (i.e. Do var privateKey = cert.PrivateKey and see whether you get it back).
You did not write how is the web service implemented.
if it is deployed on IIS
if it is self hosted
Your code to get certificate from store is correct. The question is where did you import the pfx - CurrentUser or LocalMachine store. You are using CurrentUser store in the code example. If you imported the certificate to LocalMachine store it will not be found. Also, please specify the store name - StoreName.My (in MMC or certmgr.msc it means Personal) in the constructor of X509Store (it might be default, but who knows all the defaults anyway :) )
But when I do this, then the web service barfs at me, claiming it
needs a "SSL certificate"...
You need to ensure you have Client Authentication in the extended key usage of the certificate.
Also: when I was loading the X509Certificate2 from disk, from that
*.pfx file, I had to provide a password - nothing needs to be provided here, when loading from the cert store.... odd....
It's how it works. When you have a pfx then the private key in it is secured/encrypted with password (password can be an empty string). When you import pfx to certificate store then the private key is secured/encrypted with other key (not exactly sure what key it is). However you can add another level of protection to the private key by specifying strong protection when importing pfx to the store (I do not recommend it when used with ASP.NET, or web services or anything that does not have a desktop). But when it is your personal certificate to sign emails then it might be good to enable it. Windows will then popup a window whenever an application will try to use the private key.
#DanL might be right about the rights to the private key and his
1) - set rights on private key and
2) - accessing private key in X509Certificate2
are written OK. I would just add to 1) that you are trying to connect to the REST service from a ASP.NET application or another web service on IIS then the name of the account that you need to add permission for is IIS APPPOOL\name_of_the_apppool_your_app_runs_under