I have a custom STS built with WIF. If I have the Relying Party and STS on the same server, I can get it working.
However, I'm getting ID4036 errors when using a remote machine. As I have dug into it, I found that by default in my STS was always encrpyting the outbound token with a local certificate rather than the certificate requested by the Relying Party. One solution would be to install the certiicate used by the Relying Party (public key only) on the STS and code the STS to use that certificate.
However, that creates a problem as I add other Relying Parties on different servers.
Here's an Example:
STS on MySTS - signs tokens with SigningCert.
Relying Party on MyWebServer01 - wants to encrypt/decrypt with MyWebServer01Cert (owns public / private key)
I can install MyWebServer01Cert on MySTS and set the STS to use that for encrypting tokens, and everything should work. However, let's say I want to add a Relying Party application to MyWebServer02. It will not work unless I install the public and private key of MyWebServer01Cert.
I would think that you can simply transmit the public key to the STS and each RP can use it's own - somewhat like SSL. Is this not the case?
Any help / suggestions would be appreciated.
First of all, for encryption only the public key is needed. You actually never want to give away the private key of a certificate.
If you use the WS Federation protocol (usually used for STS scenarios on web sites) the request to the STS is not sent by your RP server, but by the browser of the user. I doub't that you call tell the browser to use the public key of the previous site for communication over https. The encrypted token on the other hand is decrypted by the rp server (meaning that the RP server must know the private key of the certificate used to encrypt the token).
Taking this circumstances into account I am pretty much sure that the public key of the certificate of the RP must be present on the STS and can not be included in the request. Everything else would probably be a dirty hack only working with your custom STS (e.g. including the public key as a paramter).
At least for "passive sign-in" scenarios. For WCF you could attach the certificate of your server as client certificate to your request. But I haven't tried this by myself.
Related
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.
I'm creating Java appliation, where I will need users to log in. Currently I'm verifying if I can configure Keycloak safe enough. I'd like to make sure my application is really authenticating users against my Keycloak server - eg I know there is something like DNS Poisining or other attacks, where my application could get to attackers server with duplicated/attackers Keycloak instance. What surprised me, I have currently configuration with follwing keys:
keycloak.auth-server-url=...
keycloak.realm=...
keycloak.resource=...
keycloak.public-client=true
keycloak.security-constraints[0].authRoles[0]=..
keycloak.security-constraints[0].securityCollections[0].patterns[0]=...
keycloak.principal-attribute=preferred_username
and no public key is needed. Even worse here: https://stackoverflow.com/a/40516696/520521 I see upvoted comment telling, my application may download key from (malicious) server.
Are there any extra steps I need to follow, to authenticate Keycloak server before starting to authenticate users against it?
Based on your configuration, it seems that you've defined your client in Keycloak as public. This allows your client to be able to call Keycloak without any authentication. This type of client is used for example when you're going to authenticate via js in webpage in which nothing can be hidden from attacker as they have access to the source of the page.
If you set the "Access Type" of your client to "confidential" (in Client Settings on Keycloak Admin UI) and save the settings, there will appear another tab (next to "Setting" tab of the client) titled "Credentials". There you can see the default secret that is created for your client. You should then put this secret as below in your keycloak.json file inside your application:
"credentials": {
"secret": "paste-the-secret-value-here"
}
You can also re-generate the value by selecting the "Regenerate Secret" button.
You can also change the "Client Authenticator" there and set it to "X509 Certificate". Then you would be asked to define a regular expression to validate the "Subject DN" of the certificate that client will be using for authentication. Any certificate matching that regex would be considered as valid and authenticated. Then you have to setup your client to use such certificate instead of defining the "secret" value in the keycloak.json file.
There is of course another option which uses "Signed JWT" which is also secure and you can find the details about how to set it up in Keycloak documentation at Client Authentication section.
I can't see a word that this is the aim, but seeing where public and private key is placed I understand that answer is, that in realm settings -> keys -> active there is list of keys. You may download public key or certificate with button on right side. In my case of Spring boot, enter application.properties file a public key under keycloak.realm-key.
We are trying to implement the following workflow:
generate private key in browser, using window.crypto
create a PKCS10 certificate signing request in the browser
send the PKCS10 to a server
the server signs the request and returns an x509 certificate in PEM format
the browser stores the certificate for itself
The same thing already works using the keygen tag in the browser and using SPKAC instead of pkcs10. Now, however the browser does not store the certificate returned, just wants to save them. When we try to import the certificate to the browser by hand, we got "the private key for the certificate is missing or invalid".
We suspect that the private key generated by window.crypto.generateKey() does not get stored in the browser's keystore. How to get the private key stored in the keystore?
The implementation of the first two steps is based on http://blog.engelke.com/2014/08/23/public-key-cryptography-in-the-browser/
Update: As some browsers use the OS keystore, I am also looking into the possibility to save the key into the OS keystore through some other way.
What I have figured out so far:
Java cannot be used according to this question: Tell Java to use Windows keystore
In Windows one can use ActiveX controls.
Summary: Found no standard cross-browser and cross-OS way to generate and meaningfully use X509 certificates. There are combinations (new chrome versions (dropping keygen support) on non-windows OS) where there is no way to do this.
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
Good morning fellas !!
I have a question regarding WS-FEDERATION.
We have a partner (IDP initiated and SP Hosted) that is configured with WS-FEDERATION.
They use ADFS and we use OPENAM (we are the SP)
Everything is set up fine and running smoothly.
But their certificate is going to expire soon and we have to update it.
So from what I saw here what we are suppose to do :
Export the SP and IDP metadata , replace the X509 Certificate value with the new one then import those configuration back.
Is that correct ?
I am using OPENAM, and they have the ssoadm command mapped with a GUI.
So I exported both of those metadata, I replaced the certificate value and we will re-import them with the partner at the same time.
I never did that change, and I want to make sure that it is the proper way and that I am not missing anything !
Thank you for the help :) :)
In this situation you will find that ADFS has interim phases i.e.
Old certificate
Old and new
New
During the middle phase, you need to get the ADFS metadata and re-import into OpenAM.
That way there will be no down time as both certificates are catered for.
If you wait until the third phase, there will be some downtime until you have done the new import.