0

Situation

We have a single page web app that allows user to Drag'n'Drop their certificate and private key into it. These are then used to authenticate at the web service.

While browsers are able to perform a TLS handshake including client authentication via HTTPS, they only use the certificates installed in the OS certificate store (e.g. Chrome on macOS or MS Edge on Windows) or in the browser's certificate store (e.g. Firefox).

There is, however, no way to supply a certificate/private key to the request APIs provided by the browser as standardized by the W3C. (E.g. fetch() only allows to specify if installed credentials should generally be included or not.)

Question

Is it reasonable to implement some kind of additiona; "TLS bridging" service in our situation?

This would work as follows:

  • The bridging service accepts the certificate by the client (e.g. via HTTP),
  • ...synchronously initiates a handshake with the real client authentication service
  • ...and responds by passing down the TLS handshake challenge to the client.
  • The client is able to solve the challenge with the dropped private key and send it back by an additional HTTP request
  • The bridging service can then respond the result of the handshake/request (e.g. the auth token)

UPDATE 1:

Constraints

The following technical constraints are set for now:

  • JS-only solution in the web app (e.g. no Flash)
  • Private key of the client must not be transmitted to any server
  • Manual installation of certificate on OS/browser must not be necessary.

UPDATE 2:

As of March 20, 2018 the W3C lists the Web Authentication Standard as "Candidate Recommendation" which would solve the described issue in offering standardized API to perform client authentication. The MDN docs are also quite informative on the usage of that API in the current state.

3

There is no way to split the TLS handshake into three parts in the way you envision, i.e. that part of the handshake that comes from the original client, part from the "TLS bridging" service and part from the server.

One reason is that the Finished message from the client side can not be constructed in a way that the server will accept it: The Finished message needs both the master secret and also a hash over all handshake messages. But since the master secret is only known to the original client and all handshake message are only known to the TLS bridging service (since it has added messages to the handshake) neither the original client nor the TLS bridging service has all information needed to construct the Finished message.

All you could do is create a full man in the middle proxy which results in a full TLS connection between client and bridging service and another one between bridging service and server. Of course the bridging service would then need to recreate the original server's certificate by using its own CA and the client would need to trust the CA of the bridging service.

  • Thanks a lot for the answer. It indeed would be in our control to implement the latter. However, your outline pointed us to the fact that such a "full man in the middle proxy" would require us to re-implement TLS on application-level which seems more like an interesting paper than in feasible reach for us at the moment. Also... scary... – Leo Selig Apr 3 '18 at 13:54
  • 1
    @LeoSelig: the full man in the middle does not need a reimplementation of TLS. This is what SSL man in the middle proxies (like implemented in firewalls, squid proxy SSL bridging, mitmproxy ....) already do with the exception that in your case also a specific client certificate need to be provided for the connection between proxy and server. – Steffen Ullrich Apr 3 '18 at 14:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.