droe / sslsplit

Transparent SSL/TLS interception
https://www.roe.ch/SSLsplit
BSD 2-Clause "Simplified" License
1.73k stars 327 forks source link

Force downstream client certificates #257

Open derOnkel2 opened 4 years ago

derOnkel2 commented 4 years ago

Hi, will it be possible to force sslsplit to ask for client certificates? The upstream dispatch with "-a" and "-b" works fine but i have an IOT device that refuses tls connections if the (mitm) server does not specifically asks for its client certificate. Danke

sonertari commented 4 years ago

Hm, I see the issue, but how do we selectively request client certificates from certain clients only? I guess such an option would be all (for all clients) or nothing.

derOnkel2 commented 4 years ago

All or nothing would be fine. A different approach would be if the real server wants a client certificate, then sslsplit could also ask for one.

sonertari commented 4 years ago

Is your IoT client going to establish the ssl connection if the original server does not ask for a client certificate? I thought you meant that it never does without it.

derOnkel2 commented 4 years ago

The original server always asks for a cc. I just thought, the other option would be more generic.

derOnkel2 commented 4 years ago

I tried to figure out for myself how to add client certificate request into the code. But pxyconn.c and ssl.c are really a lot of code an probably beyond my skills. Do you have any hint where to start to modify the connection process in the code? A quick and dirty approach would do. Thanks.

sonertari commented 4 years ago

Since you're willing to develop this feature yourself, can you add the following line to the end of the function pxy_srcsslctx_create() in pxyconn.c right before it returns before the line 837?

SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);

I am not sure if this will be enough, or if it requires a verify callback too, but I hope this helps. This can of course be a quick and dirty solution only (if it works) as you mention.

derOnkel2 commented 4 years ago

Unfortunatly i get: Error from src bufferevent: 0:- 337100934:134:certificate verify failed:20:SSL routines:380:tls_process_client_certificate I tried inserting a pseudo callback static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) function as in the openssl documentation but that didn't affect anything.

Do i need to specify the CA for the client certificate? Changing the cc in the IoT device with one signed with my mitm-server-CA did not help. Or maybe my problem lies somewhere else. Thanks anyway

sonertari commented 4 years ago

Can you add the following line after SSL_CTX_set_verify() call?

SSL_CTX_set_default_verify_paths(sslctx);

Also can you remove the SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag from the second param of SSL_CTX_set_verify()?

You may need to play with the trusted CAs as you have tried before (add your CA to the store, to the device, etc.), because the client certificate may not be verified using the default certificate store.

derOnkel2 commented 4 years ago

I tried all kinds of combinations without success. Since i get no information out of my device i rebuild a scenario to get some client side output: public web server <-> AP with sslsplit <-> netbook with curl to test

Either with a client certificate signed by the original server or signed by the sslsplit-fake-CA the connection with activated SSL_VERIFY_PEER fails.

i get this curl output:

sonertari commented 4 years ago

Curl gives an unknown ca alert, which means that you did not add the sslsplit CA to the curl trust store. (Are you sure your original problem was related with client certificates? How did you determine that? Perhaps it's the same problem with this curl alert.)

But if this alert is issued by sslsplit, then the sslsplit trust store does not like the CA of curl (I am not familiar with this debug output), in which case you may need to add curl's CA to sslsplit.

derOnkel2 commented 4 years ago

The CA is the same as you can read in line 4 (serverCA.pem). The command is curl --cacert serverCA.pem --key client.key --cert client.crt https://url... The client.crt is signed with the very same CA. And it works flawless if i use sslsplit without the SSL_VERIFY_PEER option (or without SSL_VERIFY_FAIL_IF_NO_PEER_CERT but that is not what i intend)

sonertari commented 4 years ago

So, my current theory is that client cert procedure is actually running, but it is failing because sslsplit rejects the curl's client cert, because the sslsplit's default cert path does not have that CA. Can you add that CA to the default cert path of the system that sslsplit is running on? (Just because we use that CA to forge certs on sslsplit, it does not mean that it is in the default cert path of sslsplit.)

derOnkel2 commented 4 years ago

i added the CA cert to /etc/ssl/certs via /usr/local/share/ca-certificates/extra and 'update-ca-certificates' and i also added it the code with

mem = BIO_new(BIO_s_mem()); BIO_puts(mem, "serverCA.pem"); mycert = PEM_read_bio_X509(mem, NULL, 0, NULL); X509_STORE_add_cert(SSL_CTX_get_cert_store(sslctx), mycert);

still the same error on sslsplit side Error from src bufferevent: 0:- 337100934:134:certificate verify failed:20:SSL routines:380:tls_process_client_certificate and 'unknown ca' on curl side

sonertari commented 4 years ago

The unknown ca alert clearly says that openssl does not like the CA, but if you think that you have done everything right, then I am out of ideas. Perhaps my original suggestion, using an SSL_CTX_set_verify() call, was not enough or even wrong. Sorry. (I should try this myself, hopefully soon.)

derOnkel2 commented 4 years ago

Nevermind, thank you very much for your time!

derOnkel2 commented 4 years ago

i think i got it: SSL_CTX_load_verify_locations(sslctx, "/tmp/serverCA.pem", NULL); did the trick.

sonertari commented 4 years ago

Good to hear that it works with SSL_CTX_load_verify_locations(). But it is strange because you had already tried SSL_CTX_set_default_verify_paths() and added that CA to the default store, which was supposed to have the same affect. Anyway. I think the actual solution should really use SSL_CTX_set_default_verify_paths(), but whatever works for you is fine as a quick solution for now. Thanks for reporting back.