WCF trust client certificates only from one root ca - wcf

When securing WCF services with server and client certificates there is an easy way to ensure the identity of the service provider certificate (server certificate), by comparing the public key or finger print of the sender certificate with an expected value.
On http://msdn.microsoft.com/en-us/library/ff648360.aspx this is explained in step 8. You can config your app.config file in the endpoint section with an identity element where you can pass in the expected encoded finger print value of the server certificate. A comparison between received service certificate and expected value ensures I am talking to the server I expect.
But now I consider the servers point of view. The server can have several RootCA certificates in its certificate store. If the client certificate send from the requester was issued (and signed) by one of these RootCA my service will trust this client certificate. How can I ensure that my service will only trust certificates issued by one determined RootCA? And how can I configure the one trusted RootCA?
(I think this could be some kind of an equivalent way of certificate pinning for client certificates issued by on RootCA)

The only way to achieve this would be to roll your own custom x509 certificate validator. Then for each incoming request you can simply check to make sure the client certificate was issued by your root CA. It's actually quite easy to do. You can find the steps to implement this here:
How to: Create a Service that Employs a Custom Certificate Validator

Related

Mutual Authentication TLS

What is the use of mutual authentication in TLS without restricting the client cert?
Here is my understanding about client/mutual auth using TLS.
The idea is that both the server the client authenticate/verifies each other certs so,
1- The client verifies the server cert based on its CA trust store
2- The server verifies the client cert based on its *CA trust store*
Now the key point to me is the second one, the server has to trust the client certificate by either saving it in the server trust store, or save the CA/ICA of the client cert, which should be private to the client, not via public CA, private CA to that client that the server wishes to trust.
Now [rfc5246][1] says the following
If the client has sent a certificate with signing ability, a digitally-signed
CertificateVerify message is sent to explicitly verify possession of
the private key in the certificate.
This won't achieve any authentication correct? for example, if I have a server that trusts any certificate signed by the trusted CAs around the world, then why bother at all with client authentication at all?
[1]: https://www.rfc-editor.org/rfc/rfc5246
When the server gets the client cert (as part of the TLS protocol), the server does all the normal cert checks, including chaining up to a trusted root. For the server to trust a client cert issued by Foo CA, the server needs to have the Foo CA root already installed at the server.
The corner stone of X.509 certs is root CA certs. A host should only trust certs issued by the CAs it trusts. So when an admin installs FooCA's roots, the admin is stating "I trust the certs issued by Foo and I trust that Foo did appropriate checks that the cert is valid and assigned to the correct entity."
The server does not need to store the client's cert, there's no reason to. When the cert comes in as part of TLS, the server simply checks it. No persistence needed, and if anything fails, and that includes not having the Foo CA root cert installed, then the connection fails.
The server DOES authenticate the client. A certificate binds a public key (in the cert) to an entity; for example CN=frodo#theshire.com. When the client connects and the server asks for the client cert, the server will check that the name in the cert (frodo#theshire.com) matches the name of the user, but it will also get the client to encrypt some data using the private key associated with the public key in the cert, and if the server successfully decrypts the data, then the client (frodo#theshire.com) really is who they claim to be. Or, in the worst case, an imposter who got access to Frodo's private key :)
Does that help?

Restrict TLS mutual authentication to specific TLS certificates

There is a PKI with a single CA issuing all the x509 certificates in my network.
So on my network all the servers and clients possess a certificate from my CA stored in their corresponding keystore together with the private key. Each server and client has also the CA certificate in a chain file available to validate the trust chain of the peer x509 certificate when TLS mutual authentication is going on. All fine.
Let’s suppose I have now on my network two servers and two clients and I want to make sure Client_A and Server_A succeed with TLS mutual authentication using their x509 certificates, as Client_B and Server_B should do.
At the same time, I want to make sure TLS mutual authentication between Client_A and Server_B will not succeed. (Also valid between Client_B and Server_A).
How can I make the servers and clients in my network not only verifying the trust chain, but also respecting some kind of whitelist?
Maybe this is not feasible on TLS Layer, that is what I want to have clarified.
You can achieve this using any of the below 2 approaches-
Verifying client certificate at TLS layer: Create separate intermediate issuing CA for each client group. For example, for all the clients of Server_A, create a CA named Ca_Client_A. So your chain will look like rootCA -> Ca_Client_A -> client certificates. Import this Ca_Client_A in the trust-store of Server-A. Now Server_A will allow connections to the clients which has issuing ca Ca_Client_A. Similarly, you can create Ca_Client_B intermediate CA for serving client group B by server B.
Verifying client certificate at Application layer: For this, you need to write authentication logic in your application server where you need to put constraints such as allowed client certificate-serial numbers or CN name matching with keyword for successful authentication.
Hope that helps.
There isn't any way (that I know of) to do this at the TLS layer.
Most TLS libraries offer a callback option during the certificate exchange, and that would be the appropriate place to check the certificate against a list. Returning the library-specific version of failure/unacceptable will usually cause a TLS handshake failure, and no data will have been transmitted.
A lot of this depends on the server software you are using, not the TLS standard itself. Some software packages can be configured to trust certificates issued by a particular CA certificate. In your scenario, this would allow ANY certificate issued by your CA to connect to ANY server configured to trust your CA certificate. Other server software can be configured to trust a particular certificate, or certificates with a given subject (distinguished name of the certificate, subjectAltName, etc.) So, it depends on which particular "server" you're trying to connect to. Is this an Apache web server? IIS? Tomcat? The answer varies depending on what server platform we're talking about.

SSL/TLS handshake between Websphere MQ Server and Client

I'm debugging SSL errors between Websphere MQ Server and Client using T.Rob's suggestions and need help understanding the SSL handshake (SSL connect to MQ using .net mq client SSLV3?).
My WMQ 7.5 client application is C code and uses a keystore (.kdb). Utilizing a CHLTAB provided by the WebSphere admin. The WMQ server is running Java and the channel is defined with mutual authentication.
The article states that in the SSL/TLS handshake, the server always sends its public certificate in response to a connections request. The client then must validate that certificate by first checking the signature and validity date, then looking in its trust store for the thing that signed the certificate.
Here's my confusion: Since my keystore on the client side has only the application personal cert, how does the client validate the public certificate sent by the server? I have provided the Common Name of my application cert to the WebSphere server admin but nothing more than that.
Thanks in advance for the clarification!
The bit about "my keystore on the client side has only the application personal cert" is troubling. That won't work. The client KDB must have the server's public key. If the MQ server has SSLCAUTH(OPTIONAL) the the server's public cert is all that's required in the KDB for the connection to succeed.
The first part of the TLS handshake is where the client validates the server's certificate. The use of public/private key pairs is how the authenticity of the thing on the other side is assured. In order for that to happen the server must have its own personal certificate and the client must have the public key of the root of the signer chain. In the case of self-signed certificates the public portion of the personal cert must be trusted by the client. In the case of CA-signed certs the CA Root must be trusted by the client. Whichever one it is, the client must trust something used to sign the server's personal cert or that cert can't be validated.
The TLS handshake is symmetrical so the second part works exactly the same as the first but the roles are reversed. Therefore, in cases where mutual authentication is enabled the client must have its own personal cert (because that contains the private key) and the server must trust whatever signed the client's matching public key. If the client cert is self-signed the QMgr has to trust it. If the client's cert is CA-signed, the QMgr must trust the signer. Either way, the QMgr has to have a cert to validate the client in its KDB.
Following this logic, for anonymous client connections the required parts are the personal certificate in the QMgr's keystore (because it contains the QMgr's private key), and the matching trusted certificate in the client's KDB or for Java the Trust Store. Neither of these is optional.
If the client is to be authenticated you still need the same two certs as for anonymous clients because that part of the handshake has to complete before the client is authenticated. In addition, now you also need the client to have its own personal certificate (because it contains the client's private key) and the QMgr now needs to trust whatever signed the client's certificate - the client cert if self-signed or the signer root if CA-signed.
As a side note, There is also some confusion in the post because it says that "My WMQ 7.5 client application is C code and the WMQ server is running Java." There is nothing in the queue manager that uses Java on the server side. There are Java components installed to do things like manage JNDI objects and run the sample code. In modern MQ versions Java runs the Web Console. But there are no Java components in the QMgr itself and no Java components in the path of the incoming channel connection request. That's all habdled by the QMgr's listener, agent, and other internal processes. So I'm not at all sure what is being referred to there other than that the notion of Java running on the MQ server side and participating in the TLS handshake might be a source of some of the confusion mentioned in the post. ;-)

mTLS ( mutual TLS) details

I know that for MTLS , both parties , Client and server exchange certificates. These certificates should be signed by a CA that both parties can trust in order to validate the certificate.
My question is , does MTLS also means in addition to verifying the certificate (if CA is trusted, leaf certificate is trusted) , either side (Server or client) can also do some additional checks like Hostname check or Whether the client connecting to the server is in the list of approved trusted entities?
Can anyone point me to the mTLS specification and what are the overheads in mTLS?
Besides what EJP has said about "MTLS" term, the TLS 1.2 specification doesn't have strict requirements regarding what information is to be checked and in which way.
It's up to the receiving party to decide if the presented certificate is to be trusted or not. This means that for example it's ok for the server to accept only certificates issued by the CA that belongs to the company that owns the server. This is how client-bank access systems often work - they accept only certificates issued by the bank and the common name of such certificate must correspond to the username provided in a web form.
Both parties are free to check any information in the certificate including direct comparison of public key hash (thus only particular keypairs will work no matter what is contained in other certificate properties).
The most up todate RFC regarding this subject is:
https://datatracker.ietf.org/doc/draft-ietf-oauth-mtls/
this is an extension to OAuth 2.0
The purpose of this document is to define a mechanism how TLS certificate is used in a context of replacing Client ID and Secret (aka, Client Credentials)
The standard establishes two mechanisms how a TLS Certificate is used as a client credential, and the associated token flows, and attributes.
The general summary of this is:
(a) Authorization Server: checks the certificate either according to PKI (signed by a valid root) The RFC does not define the options, but they are pretty self-explanatory and depend on the use case. But it can be (1) certificate is signed by a trusted root and, is not revoked, (2) individually recognize each certificate based on some logic.
(b) Resource server checks the token and client certificate (client credential, or CC), and used in the underlying TLS session. Please note that there are no validation checks concerning the certificate or its origin at TLS layer, all checks are performed at an Application layer. The resource server should, therefore, configure the TLS stack in a way that it does not verify whether the certificate presented by the client during the handshake is signed by a trusted CA certificate.
This mechanism becomes particularly interesting in some GDPR context, as it makes it impossible to share tokens between client and the server.
Overall a great feature for privacy, and improved security.
mTLS can be implemented by issuing all parties a CA certificate and adding these to all communicating parties, which is a sort of an access control list. Whoever has their CA certificate in your app's trust store is able to connect.
The trust system however is the same as with TLS in the case of a https connection - you can issue several certificates from the same CA and add the root CA certificate to the trust store of your app. It will trust all certificates issued from the same root. This is arguably easier to set up as you only have to add the app's own certificate and the CA root. However, if you want to revoke a certificate, it becomes a little more complicated.
I wrote a guide to generate certificates here:
https://thoughts-about-code.blogspot.com/2021/12/creating-a-ca-for-mtls-with-openssl.html
First:
Both server and client certificates have to be built with the same CA certificate and key
see : https://github.com/ysimonx/mtls-ssl-generator/blob/main/generate_certificates.sh
So you have to store the CA certificate on both sides :
On the server side : you can allow (this is optional) a client that provides client cert built with the same CA than its own certificate. (see rejectUnauthorized: true)
https: {
requestCert: true,
rejectUnauthorized: true,
key: fs.readFileSync("./certificates/server/serverKey.pem"),
cert: fs.readFileSync("./certificates/server/serverCrt.pem") ,
ca: [fs.readFileSync("./certificates/ca/caCrt.pem")]
}
(exemple for a fastify nodejs https self-signed certificate server)
On the client side : you can allow (this is optional too) a server that provides (or not) the same CA certificate as the client knows
curl -k --cert ./certificates/client/clientCrt.pem --key ./certificates/client/clientKey.pem https://localhost:3000/
(parameter -k : do not verify the server certificate based upon a CA authority)
or
curl --cacert ./certificates/ca/caCrt.pem --cert ./certificates/client/clientCrt.pem --key ./certificates/client/clientKey.pem https://localhost:3000/
if you want the client to match the correct CA cert used by the server
There is no 'MTLS Specification', for the very good reason that there is no such thing as 'MTLS'. You just made it up. The TLS specification, including mutual authentication, is to be found in RFC 2246 as amended.
The TLS APIs should make the peer certificate chain available to the application, so it can do any additional checking it likes.
'MTLS', insofar as it exists at all, refers to an Internet Draft for multiplexed TLS.

SSL and public key security

I'm consuming a web service from an Android device using HTTP(s) with SSL. A self-signed (untrusted) certificate is used for client authentication.
I have a general understanding of how public/private keys are used for SSL. From my understanding I can clearly see how a certificate can be used to set up a secure connection and transmit data securely. However I do not understand how they are used for client authentication since the certificate contains the public key and is not kept a secret.
I have a few questions:
Where can I read about how SSL and certificates can be used for client authentication?
Even if the certificate was not made public...by visiting the HTTPS URL in a browser I can view and save the certificate. I can then package up the certificate in a key store and use it from an application.
In this post Jeremy Huiskamp writes
client auth will automatically be performed when the server requests
it
...so client authentication as well as encryption of data can be performed with certificates?
Edited to answer the first part of my question: The client keystore should contain not only the server's public key but also the client's private key. The server must then be able to decrypt using the client's public key? Does this mean the keystore should have two certificates?
First, a quick point about the terminology in public key cryptography:
you sign and decrypt/decipher using a private key,
you verify (a signature) and encrypt/encipher using a public key.
(You don't really "decrypt" using a public key.)
Using SSL/TLS with or without client-authentication, the server presents a certificate (*) for which it has the private key. The server sends its certificate during the SSL/TLS handshake (at the beginning of the connection) and is able to decipher what the client sends using its private key (which it keeps private). The private key and certificates are stored in the server's keystore (or equivalent if it's not implemented in Java).
As part of this, the client uses its truststore, which is a form a keystore that contains trusted certificates, to verify the server certificate. The server certificate could be trusted by being explicitly in the truststore or, in most cases, trusted by linking in to a trusted CA certificate in the truststore (PKI).
The terminology between keystore and truststore in Java can be a bit confusing, you can find more details in this answer.
Regarding your question, the client's truststore doesn't contain the server's public key, but either its certificate or a CA certificate with which it should be verifiable. (It's not just about having the public key, but knowing whose it is, using the other pieces of information in the certificate.)
When you use client-certificate authentication in addition to this, there is a truststore (or equivalent) on the server side and a keystore on the client side too, since the roles are reversed for this purpose.
In the SSL/TLS handshake that uses client-authentication, the server requests a certificate from the client, who sends it (if available).
At the end of this handshake, the client sends a CertificateVerify message, which signs all the messages exchanged so far between the client and the server (so it's something known to both) using the client certificate private key. The server is then able to verify this signature against the public key within the client certificate it has obtained as part of this exchange. This proves to the server that whoever is on the client side has the private key corresponding to the public key in the certificate it has sent.
The next step for the server is to verify whether to trust this certificate, i.e. whether to trust the binding between identity and public key as presented and "sealed" within the certificate.
This is usually done using a PKI, whereby you check the certificate against a known CA, or if your deployment environment is sufficiently small, against a fixed set of trusted certificates. (There can be alternative methods of verification, but their usability will really depend on the circumstances where you want to deploy this system.)
Therefore, for your second question:
The client keystore should contain at least the client's certificate and its private key.
The client truststore should contain the server certificate or a CA certificate with which the server certificate can be verified.
Since both keystore and truststore are a keystore (in the storage format sense, usually a file) used for a different purpose, it's often possible to use the same keystore to serve both the purpose of keystore and truststore.
(*) There are cipher suites that don't rely on certificates, but that's unusual and off topic for this question.
A certificate just binds an identity to a public key. This binding is not secret, so there is no need to keep the certificate secret. If I have John Smith's certificate, I can prove that John Smith owns the secret key corresponding to a particular public key. But since I don't know that secret key, the certificate is of no use to me.
When authentication occurs by certificate, one step is always to have whoever presents the certificate prove they know the secret key corresponding to the public key in the certificate. If you cannot pass that step, the authentication fails.
The server's keystore should have the server's certificate. The client's keystore should have the client's certificate. The client will present its certificate to the server, so the server will learn the client's public key that way. (And vice-versa.)