Search code examples
javasslx509trustmanagergemini

Security implications of trusting all client certificates on a server (Java X509TrustManager)


A custom "empty" X509TrustManager implementation (i.e. one that trusts all certificates, such as this answer: https://stackoverflow.com/a/54358567 or "option 2" in this answer: https://stackoverflow.com/a/2893932) is often recommended on this site and others. People (rightly) criticise this as insecure and dangerous advice. This is usually being used in clients to trust any server certificate.

I want to know if this practice is necessarily unsafe for a server trusting any client certificate (assuming said certificate is then checked separately against a list of trusted certs).

Context: I'm trying to create a basic Gemini server (https://gemini.circumlunar.space/docs/specification.gmi). Most pages served will not require a client certificate, but I don't want to fail the TLS handshake if a client presents a random certificate. Some pages (e.g. a log viewer for admins) may require a specific client certificate (e.g. with a public key stored on the server at a hardcoded file path). Other pages may want to trust a dynamic list of certificates (e.g. from a database of registered users).

If I create a custom X509TrustManager that trusts all client certificates and use this in my SSLServerSocketFactory:

  1. Will certificates returned by clientSocket.getSession().getPeerCertificates() still have been pre-validated against their private keys (i.e. if someone presents the admin cert, but doesn't have the private key, will getPeerCertificates() return an empty array)?
  2. Is there any risk to also leaving the checkServerTrusted()/getAcceptedIssuers() methods in my TrustManager blank/null? If this TrustManager is only used by my server socket factory, will these methods ever be called?
  3. Is there a better way to achieve what I want?

Solution

  • I want to know if this practice is necessarily unsafe for a server trusting any client certificate (assuming said certificate is then checked separately against a list of trusted certs).

    Requesting but not validating the client certificate does not introduce any security issues compared to not requesting a client certificate in the first place.

    Using a client certificate for authentication without validating it instead obviously adds problems, since an attacker could present a self-made certificate in this case. But as you wrote, the client certificate will be (hopefully properly) checked outside of the TLS handshake later before accepting is for authentication. In this case it is perfectly safe to not check it inside the handshake.

    I want to know if this practice is necessarily unsafe for a server trusting any client certificate (assuming said certificate is then checked separately against a list of trusted certs).

    Even if certificate validation is off it will still be verified that the client owns the presented certificate, i.e. that it has the matching private key.

    Is there any risk to also leaving the checkServerTrusted()/getAcceptedIssuers() methods in my TrustManager blank/null? If this TrustManager is only used by my server socket factory, will these methods ever be called?

    checkServerTrusted will be called to check the server certificate, i.e. only on the client side. So this function does not matter. I'm not sure aboutgetAcceptedIssuers - maybe it gets called when sending over the list of accepted CA to the client. It should not matter if this list is empty though.