I'm setting up 2-way SSL communication between services on different hosts. Let's say I have my own CA called A. A is trusted by all of my services through a centralized jks. Now let's say I have certificate B signed by A. When services send the certificate should they be sending the entire chain B - A, or just B? I believe both tend to work with most implementations.
I tried to find canonical information about this online, but I'm coming up with nothing.
Thanks for the help
As per tls - Validating an SSL certificate chain according to RFC 5280: Am I understanding this correctly? - Information Security Stack Exchange:
the server should send the exact chain that is to be used; the server
is explicitly allowed to omit the root CA, but that's all.
Reference (RFC 5246 - TLS v1.2, sec. 7.4.2. - Server Certificate):
certificate_list
This is a sequence (chain) of certificates. The sender's
certificate MUST come first in the list. Each following certificate
MUST directly certify the one preceding it. Because certificate
validation requires that root keys be distributed independently, the
self-signed certificate that specifies the root certificate
authority MAY be omitted from the chain, under the assumption that
the remote end must already possess it in order to validate it in
any case.
The idea behind the trusted root CA is that it is trusted. Would you expect the browser to trust anything sent by the server just because it includes a root CA? No!
Therefore the root CA must be already at the client and must be trusted there. It should not be included in the certificate chain by the server, but if you do it anyway browsers will simply ignore it.
Related
Does a non-self-signed certificate, imported into root store, require a (self-signed) issuer to also be imported into the root store?
Suppose I've a certificate A that is signed by another certificate B. Is it then sufficient to only import A into the root store, i.e. certificate validation stops at A, or should B also be imported into the root store for proper certificate validation?
The reason I'm asking this question, is that I've encountered different results with different products (e.g. web browser or system), and so I want to know the right way.
You should include Cert B in truststore. As mentioned in the comments, your mileage may vary as clients, as well as servers, implement RFC differently.
In terms of rules, spec for x.509 certs is in IETF RFC 5280. The key information is that for SSL handshake to happen client should do a full cert chain validation, which ends up with a self-signed certificate that is in your trust store.
Your Cert is not self-signed, it is issued by a different CA (cert B). If you do not have B in your truststore, then trust chain is broken. However, again as mentioned above, it is possible that client will not validate the full cert chain.
Think of it this way. Your client is presented with Cert A, which is signed by "B". Client should verify that signature on A is fine, which means it needs (certificate of) "B". If B is a "root" CA or self-signed, its "issuer" and "subject" fields will match. And if that Cert B is in your TrustStore, you are golden.
It's the job of the server to send you a certificate list for TLS.
This is a sequence (chain) of certificates. The sender's
certificate MUST come first in the list. Each following
certificate MUST directly certify the one preceding it.
There is a visual representation of certificate chain verification here. Hope it helps.
When a TLS handshake takes place, the server sends in his ServerHello message, his digital certificate. This digital certificate is digitally signed by a intermediate CA named A and CA A also has a certificate which is signed by CA named root whose certificate is self signed, thus forming a certificate chain. The client then has to establish a trust, validating the server certificate. To perform that validation the client has to validate the entire chain correct?
Must the client have in a truststore all the certificates (A and Root) or the client will download them?
The client usually has only the root CA in the local trust store. The leaf certificate and the intermediate certificate leading to the root CA need to be provided by the server. The intermediate certificates are usually send in addition to the leaf certificate within the TLS handshake.
But it is a typical misconfiguration to only have the leaf certificate send by the server. In this case the certificate validation will fail unless the client has already knowledge of the intermediate certificates or can obtain these somehow. Since often the same intermediate certificates are used, some browsers like Firefox will cache the intermediate certificates they'll got when communicating with server A and fill these in when a broken server B is not sending the required intermediate certificates. Other browsers (like Google Chrome) will try to download the missing intermediate certificates from the internet. Most simpler clients (i.e. apps written in Python, Java ... or curl) will instead just fail with a certificate validation error.
I've been googling like mad trying to figure this out, but the answer doesn't seem to be clear, or at least, it seems like there are contradictory answers.
I'm tasked with setting up an Apache web server with 2Way SSL authentication. We use verisign to get our certificates, so we have a certificate for the web instance with the correct hostname details, signed by verisign, and an intermediate certificate from verisign. This all works very well.
Now, we need to set up a 2Way SSL connection. The initial expectation is that the client will manage their own certificates, and provide them to us for authentication. More than one client may be connecting, and they should each have access to different resources when they connect.
From what I've read, I'm not sure how this would be done...
This is a pretty good overview, but in this situation, they are using self-signed certificates: https://security.stackexchange.com/questions/34897/configure-ssl-mutual-two-way-authentication
Using these details, it would seem like we would have to make the trusted CA point to the certificate authority that signs the client's certificate.
Is it possible to use the client certificate as the trusted CA (even though it isn't self signed, but signed by a CA) or would we have to put a trusted CA from their signer (and at that point, would a CA bundle that includes all the client certificate authority CAs work?) on the server and then use the SSLRequire statements to limit access to specific details of the certificate?
As a followup, can we use the SSL Certificate that we get from verisign to sign client certificates?
So, after several more hours on google, and some testing, I was able to figure out what I needed to.
If I want to use a certificate signed by verisign or some other public CA, I would have to copy their public intermediate certificate (the one that they use to sign the client certs) to my server and specify it as the SSLCACertificateFile in the configuration. The caveat is that then any cert signed by that CA would be accepted, and that's where the SSLRequire directives can used to narrow that down to specific certificates.
Using the SSLVerifyClient optional_no_ca directive would make it assume that the cert is trusted, even if it isn't, and then I would have to use SSLRequire directives to verify the details are correct, however, anybody could create and sign their own certificate with those details and there would be no way to tell.
Creating my own self signed CA certificate, and then using that to sign the client certificates and issuing them to the clients is the only way to both ensure that the cert isn't a forgery and not requiring SSLRequire directives to ensure that only the people that I specify can connect.
Please comment/correct me if I'm wrong on any of this.
Use:
SSLVerifyClient optional_no_ca
In your Apache config. This will request the client certificate but not validate it against a CA. It will then be up to your local script to examine the resulting environment variables set by Apache such as 'SSL_SERVER_S_DN' and decide whether to allow the request or not.
These mod_ssl environment variables are also what your code needs to look at when determining what resources the client can access.
The full documentation is here mod_ssl although you probably found that already.
A note on client certificates. If you did want to use a CA and leave it to the clients, they may all use different CA's and you would have a job maintaining them all on your server. It would be much better to trust a single CA.
The advantage would be that then you could use the build in SSL support to do all your certificate checks and not write your own solution.
You could enforce a single CA by specifying an on-line provider and using email signing certificates to identify clients. These would work fine, just the Certificate Subject would be an email address instead of a domain name.
Or you could set up your own CA and sign client certificates yourself. This is not too difficult and gives you complete control. Either route would require you to add the CA root certificate (plus intermediates) to a file Apache can read and point 'SSLCACertificateFile' to it.
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.
According to https://wiki.jasig.org/display/CASUM/X.509+Certificates,
After the Server sends the certificate that identifies itself, it then can then send a list of names of Certificate Authorities from which it is willing to accept certificates.
I am wondering how to determine what this list is, and how to modify it.
The reason I am asking is that I am getting an infinite redirect between my server and my client after successful validation (i.e., the ticket stage), and I think it has to do with the CAS server not recognizing the CAS client's certificate (the client's certificate is self-signed).
If you want to see what this list is, you can use OpenSSL:
echo "" | openssl s_client -connect your.server:port
This will show various messages regarding the handshake, including the certificates and the list of CAs in the CertificateRequest message.
Ultimately, it's determined by the active X509TrustManager's getAcceptedIssuers() method. By default, this will be the list of Subject DNs of all your trust anchors (that is, the Subject DNs of all the certificates in your trust store).
Your client certificate will have to be verified by the server. This is normally done during the handshake by the trust manager, which (unless tweaked) will build a chain to a known CA (or at least known cert if it's the user cert itself) in the trust store.
Adding your self-signed certificate to your trust store should be sufficient. It doesn't have to be the cacerts file bundled with the JVM, you could make a copy of it and use the trust store settings of Apache Tomcat's connector to set it up.