I have a question on design of secure WireMock pro...
# general
p
I have a question on design of secure WireMock proxying. According to the documentation, when proxying an HTTPS endpoint, WireMock uses its CA certificate to sign that endpoint certificate to later present to the client. The client can either ignore the certificate or have the WireMock CA certificate in its truststore. Some clients cannot be configured to ignore the certificates. This leaves us with the latter option to use truststore. It my experience, this option considerably complicates the client setup and invites hard-to-debug issues. Indeed, to sign certificates on the fly, WireMock hacks into internals of JDK 17. If this is not allowed or the JDK is newer, WireMock almost silently loses that ability at runtime. That makes it very hard to figure what happened. I see a few options for fixing this. The most straightforward would be to improve diagnostics and make errors more helpful. That is, instead of a barely useful messages like
Your runtime does not support generating certificates at runtime
or
certificates cannot be generated; perhaps the sun internal classes are not available?
WireMock could suggest to use JDK 17 with
--add-opens java.base/sun.security.x509=ALL-UNNAMED
. A more involved option would be to re-implement certificate signing using a
keytool
sub-process or a 3rd party security library. However, to my mind, the most interesting option is this: don't sign the certificates at all, and instead present a fixed WireMock certificate to the client. If WireMock does this, then the entire problem will go away. The last option is based on my understanding that signing a target endpoint certificate with WireMock CA certificate does not give us any more security than just a WireMock certificate itself. It's already MITM, and the client trusts WireMock to do the right thing: WireMock should either ignore the endpoint certificates or have them in its truststore.
t
If it’s possible to do this, then that would be excellent, and it would indeed simplify things a lot. But our understanding when we did the original work is that because you’re proxying to different target domains you need to generate a separate certificate for each domain so that the CN and domain name could match. Could you create a proof of concept of what you’re describing above?
BTW, the other solution we’ve been discussing for a while but haven’t had time for is to build a small “Certificate authority” library on top of Bouncycastle and use this instead of the JDK classes.
p
Correct me if I'm wrong, but when a client connects a HTTPS server through a WM as a proxy, WM, in fact, establishes two HTTPS connections: client<->WM and WM<->server. So client<->WM is always the host of WM, no?
Disclaimer: I do know very little on PKI.
t
It’s a bit messier than that. When you forward proxy HTTPS the proxy will normally create a TCP tunnel and push the encrypted bits through it to the target. We have to intercept that, but the client must still think it’s connecting to the target domain name, hence the certificate’s CN must match the domain name it connected to.
p
Understood; it seems that option 3 is off the table. Then, perhaps, option 2 would be the way to go: JDK
keytool
or BC.
I'll have to have a look more into it. I don't think I understand how WM is able to intercept anything without knowing the session key, for which WM must seemingly know the endpoint private key.
t
Rather than forwarding the TCP stream onto the target it instead loops it back onto its own HTTPS connector, which then fakes the certificate of the target domain.
p
Thanks, I'll have a look more into it.
👍 1