MITM proxy, TLS 1.2 Certificate verification failed - c++

Trying to create my own simple MITM-proxy for the specific app which using TLS 1.2 protocol and connecting to several IP addresses, however got in stuck with the error in the app log "Certificate verify failed". How to solve this problem?
The app using about the following code to check the cert:
X509* cert = SSL_get_peer_certificate( ssl );
X509_STORE_CTX * xCtx = X509_STORE_CTX_new();
X509_STORE_CTX_init( xCtx, (X509_STORE*)Store, cert, NULL );
int res = X509_verify_cert( xCtx );
if( !res ) { /*Certificate verify failed*/ };
I did the following steps to achieve the result:
Created CA root key and self-signed certificate according to this manual. It is a bit outdated, so i have made some changes like md5 to sha256, also I didn't use pass phrase, used different key size and other minor changes.
Created proxy key and certificate using the above Root CA to sign it.
Both certificates have been added to the Local Computer Certificates in Personal and Trusted Root Certification Authorities (not sure if this was necessary). Btw, I'm using Windows 10.
Wrote a simple proxy server using sample code from here. Cert.pem and Key.pem took from the second step.
Changed all IP addresses in the app to 127.0.0.1:443 to see if TLS connection established successfully and we can receive first message with an Application Data.
I believe that connection established properly, because WireShark shows common sequence for establishing a TLS connection: Client/Server hello, Certificate, Client key exchange, two encrypted handshake messages. Moreover, using OpenSSL for testing connection:
openssl s_client -connect localhost:443
allow me to write some message and later successfully receive it using SSL_Read() in proxy server. However, there are some errors:
verify error:num=20:unable to get local issuer certificate
verify return:1
verify error:num=21:unable to verify the first certificate
verify return:1
Verify return code: 21 (unable to verify the first certificate)
Using OpenSSL client to directly connect to the original IP addresses give the same errors, but application works great.
Also the output:
openssl verify -CAfile "signing-ca-1.crt" "cert.crt"
WARNING: can't open config file: /usr/local/ssl/openssl.cnf
e:\MyProg\SSL_serv\Debug\cert.crt: OK
It seems that I missed something important. Could you please tell me how to solve this problem with cert?

One of the very purposes of having certificates, along with certificate authorities, is to prevent MITM. The app you are trying trick does the proper thing and checks the certificate. And it doesn't like your's. Its really that simple.
Is it possible to circumvent it and run MITM on an app anyway? Absolutely! Is it going to be easy? Probably not. What you need to do is to patch the app and remove this certificate check.

Related

How to get the CA Certificate Used to Validate Client Certificate programmatically

In a server application, once a connection has been established I can grab the client certificate from the SSL * I have. Is there a way to find out which CA I used to validate that certificate?
You can use the SSL_get0_verified_chain() function for this purpose. See the documentation here:
https://www.openssl.org/docs/man1.1.1/man3/SSL_get0_verified_chain.html
Note that this function was first introduced in OpenSSL 1.1.0, so this won't work in OpenSSL 1.0.2.
This post seems on point:
Find client certificate information from server in OpenSSL
Since SSL_get_peer_certificate returns an X509 cert, I would expect that the cert chain would be included (you couldn't handle a CRL properly without it, I'd think)?

GNU libmicrohttpd with client TLS allows empty certificate

I am using GNU libmicrohttpd to establish HTTPS server. My requirement is that the server and the client both authenticate during the TLS handshake however what I observe is that even if the client sends empty certificate the connection is accepted.
in wireshark I see that the server requests certificate and the client sends certificate with len 0. How to make the microhttpd to not accept that case - the certificate must always be verified with the provided CA pem?
if(!(server_handle = MHD_start_daemon(flags, port, NULL, NULL,
&mhttpd_layer::access_handler_callback, callback_data,
// now, continue with the options
MHD_OPTION_NOTIFY_COMPLETED, &mhttpd_layer::request_completed_callback, l_callback_data,
MHD_OPTION_SOCK_ADDR, (sockaddr*) &(it->addr),
MHD_OPTION_CONNECTION_TIMEOUT, it->conn_timeout,
MHD_OPTION_CONNECTION_LIMIT, it->conn_limit,
MHD_OPTION_PER_IP_CONNECTION_LIMIT, it->per_ip_conn_limit,
// HTTPS certificate options
MHD_OPTION_HTTPS_MEM_KEY, it->https_key_buff.data(),
MHD_OPTION_HTTPS_MEM_CERT, it->https_cert_buff.data(),
MHD_OPTION_HTTPS_MEM_TRUST, it->https_turst_ca_buff.data(),
MHD_OPTION_END)))
Maybe I should manually on the access callback retrieve the certificate as described by their tutorial (https://www.gnu.org/software/libmicrohttpd/tutorial.html#Adding-a-layer-of-security) ? In this case why do I provide the CA - this doesn't seem the proper way to me?

uWebSockets (C++): secure wss server

I am using uWebSockets in C++ to host a WebSocket server. However, I need it to be a secure wss server instead of simply a ws server.
I have tried this code:
uS::TLS::Context tls = uS::TLS::createContext ("./cert.perm", "./key.perm", "passphrase");
if (h.listen (9002, tls)) {
cout << "Game server listening on port 9002" << endl;
h.run();
}
I am using this shell command to generate the certificate and key:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 30
I then tried connecting to my remote server using wss://address instead of the usual ws://address, however, it cannot connect.
Any ideas why? Thanks
UPDATE #1
The tls variable seems to be actually NULL, so it looks like the certificate part isn't working.
UPDATE #2
I got the file extensions wrong in the code, they're meant to be pem instead of perm. However, the server will now not establish a connection on both wss and ws.
UPDATE #3
After fixing the issue mentioned above, the tls variable is now 1 instead of 0 (which I assumed was NULL).
If you are using a web browser ws-client to connect to wss://address, try checking if the browser is the problem. It happened to me that I had created my own certificates, but the browser blocks the connection as they are not certified by any CA.
Enter in your browser something like: "https://address", and add a security exception for your "address".
I know you can use uWebSockets for SSL/TLS, however... I would consider separating the TLS/SSL concern from the main application.
Separating the TLS/SSL layer from the app allows you to update the TLS/SSL without recompiling the application as well as simplifies the codebase.
I would recommend using a TLS/SSL proxy or tunnel while having the app bind locally to the loopback address or to a unix socket.

Asio certificate verify failed

I downloaded Asio Standalone and would like to run the ssl example (client and server) provided with the Asio source code on my local computer. I managed to get the library running. The code compiles without errors. But I think the client has a problem reading the server certificate from the certificate store on my debian system in /etc/ssl/certs. Because I get the following error:
Handshake failed: certificate verify failed
What I did so far:
I created the server certificate and key as descripted in my last post and added the crt file to /etc/ssl/certs
I set the verify_path on client side as following:
asio::ssl::context ctx(asio::ssl::context::tlsv11);
ctx.set_default_verify_paths();
I start the server on port 8877 on my local computer
I start the client with host IP 127.0.0.1 and port 8877
then I get the error as mentioned above.
Am I right that asio finds my certificate? (because otherwise I would expect an error 'file_not_found' or something like that) Why is the certificate not valid? Because I self-signed it or because I don't use 127.0.0.1 as a 'Common Name' in the certificate ? But I guess the client should accept a self-signed certificate in it's local certificate store...

Requirements for Successful SSL Communication

I'm using thrift to write a C++ client which will call securely to the server (which is not written by me) written in java (code generated for both server and client using same thrift files). I'm a newbie in SSL communication. For the java server side, I imported the public key certificate of client to the server truststore (server-truststore.jks) to verify the client authenticity. I exported the public certificate from the server side keystore (server.jks) and used it in the client side to authenticate the server key certificate during the SSL handshake. If I list down what I did for the SSL communication:
Server Side (java):
exported the client's public key certificate to the server's truststore
Cleint Side (C++):
Loaded the server's public certificate which was exported from the server's keystore
separately loaded the client's public key and private key (This is because I can't directly use a java key store since the client is written in c++)
All the certificates used are self signed.
So far I have been unsuccessful and got the following error continuously:
SSL_connect: certificate verify failed
I have two questions:
Is the approach I used for SSL communication correct? If not, what is the correct one?
Any possible reasons for this error?
Thank you.
Check if you can verify the key invoking directly: openssl s_client -connect serverIP:Port .
If you can is problem of your code, and for that we will need more details about it.
If not... your are not using the cert. the server is sending you, or something is wrong with the certificate.