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.)
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)
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.
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.