I have windows c++ project.
Need to implement both ssl client and server on top of existing winsock code.
I tried with openssl but it seems too messy. I assume there is nicer/shorter/cleaner/faster way implementeing this than openssl..
Im thankful for any suggestions..
You can use Windows built-in SSL stuff -- SChannel . Searching Google fo "SChannel SSL" would give you plenty of information (though SChannel itself is poorly documented and not easy to comprehend).
On the other hand, OpenSSL is not messy once you study the source code of some project, that uses OpenSSL.
Acctually .. After some time spent with openssl hacking I wouldnt say its that messy :)
In case anyone anytime needs to add ssl to existing winsock code:
existing winsock code was like this:
0: sockett.Listen etc....
1: sockett.Accept(client, .....
2: recv(client , ...)
3: send(client , .....)
well in short if you want to implement SSL here..
delete lines 2 and 3 :) and add:
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *tlsctx;
SSL *ssl;
tlsctx = SSL_CTX_new( SSLv23_method());
// search google : generate self signed certificate openssl
SSL_CTX_use_certificate_file(tlsctx, "ssl\\server1.crt" , SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(tlsctx, "ssl\\server1.key", SSL_FILETYPE_PEM);
ssl = SSL_new(tlsctx);
SSL_set_fd(ssl, client);
SSL_accept(ssl);
/* instaed recv SSL_read(ssl, ....*/
/* instaed send SSL_write(ssl, ....*/
/* not 100% sure Sleep and shutdown/free/close are entirely correct here but in my code works fine */
Sleep(3000);
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(tlsctx);
shutdown(client, SD_BOTH);
Sleep(10);
closesocket(client);
For testing:
in command line run:
openssl s_client -host localhost -port <PORT>
Related
I desperately need some help on 2 questions:
I'm trying to connect a LILYGO TTGO T-Call SIM800L (IP5306 20190610) to AWS IoT, which requires an SSL authentication through a Root Certificate, a Client Certificate and a Private Key.
I'm able to successfully create the .crt files, write on them and set the Client Certificate through the AT Command:
modem.sendAT(GF("+SSLSETCERT=C:\User\clientcert.crt"));
But when I try to set the RootCA like this:
modem.sendAT(GF("+SSLSETROOT=C:\User\rootca.crt,1188"));
the GSM module returns "ERROR".
This is the documentation I'm using as a reference (Page 13):
https://microchip.ua/simcom/2G/Application%20Notes/SIM800%20Series_SSL_Application%20Note_V1.05.pdf
In the "Reference" section of the command "AT+SSLSETROOT", it's written "The files to be imported must be binary encoded". This confused me a little, so at first I simply wrote on the file the string format of the certificate, but I've also tried to change the extension to .der (which technically is the binary encoded format for certificates). I've tried to write on the file the hexdump version of the string format, and tried all the other avaiable extensions (.crt, .cer, .pem, .p12).
I've also tried to update the firmware following the procedure here: https://github.com/Xinyuan-LilyGO/LilyGo-T-Call-SIM800/blob/master/doc/How%20to%20update%20firmware.md
The only difference is that I used the Download Tool v1.10, because the other versions of the tool hanged on "Waiting" whenever I started the update. I retrieved it from here: https://simcom.ee/documents/?dir=SIM800x
I saw on other discussions that the SIM800L does not support TLS 1.2, but on page 6 of the SIM800 documentation regarding SSL, it's reported that "SIM800 series support SSL2.0, SSL3.0, TLS1.0 and TLS1.2."
On top of that, the command "AT+CIPSSL=1" works fine since it returns "OK".
I also read this: https://github.com/vshymanskyy/TinyGSM/issues/29#issuecomment-328802556
I'm attaching the function that sets up the certificates.
void setCertificates() {
modem.getModemInfo();
modem.sendAT(GF("+FSCREATE=C:\\User\\rootca.crt"));
modem.waitResponse();
modem.sendAT(GF("+FSCREATE=C:\\User\\clientcert.crt"));
modem.waitResponse();
char rootcertific[1188];
strcpy(rootcertific,rootCA);
modem.sendAT(GF("+FSWRITE=C:\\User\\rootca.crt,0,1188,1"));
modem.waitResponse(">");
SerialAT.print(rootcertific);
modem.waitResponse();
delay(1000 / portTICK_PERIOD_MS);
char clientcertific[2903];
strcpy(clientcertific,certificate_pem_crt);
modem.sendAT(GF("+FSWRITE=C:\\User\\clientcert.crt,0,2900,2"));
modem.waitResponse(">");
Serial1.print(strcat(clientcertific,private_pem_key));
modem.waitResponse();
delay(1000 / portTICK_PERIOD_MS);
modem.sendAT(GF("+FSREAD=C:\\User\\rootca.crt,0,1188,1"));
modem.waitResponse();
modem.waitResponse();
modem.sendAT(GF("+FSREAD=C:\\User\\clientcert.crt,0,2900,1"));
modem.waitResponse();
modem.waitResponse();
modem.sendAT(GF("+SSLSETROOT=C:\\User\\rootca.crt,1188"));
modem.waitResponse();
modem.sendAT(GF("+SSLSETCERT=C:\\User\\clientcert.crt"));
modem.waitResponse();
}
On page 11 of the SIM800 SSL documentation, the command AT+SSLSETCERT is described as "Client Client Certificate File with Private Key". Does this mean that I somehow have to write both the Client Cert and the Private Key on the same file?
As you might have noticed in the function, I used "strcat(clientcertific,private_pem_key)" and it returns no error, but I'm not sure whether this is the correct way to do this.
If anyone can help me out on this one I'd be infinitely grateful. It's been keeping me stuck for almost a month now.
Thank you!
I have been learning with WebSocket++ and built some of the server examples (Windows 10 Visual Studio 2019). The non-TLS examples work without issues, however, the TLS-enabled examples (echo_server_both.cpp and echo_server_tls.cpp) can't do the handshake. I am very new to web development in general so I know I must be doing something wrong with regards to the certificate and keys.
I am testing the servers with WebSocket King client, an extension of Google Chrome that connects correctly to other websocket servers like wss://echo.websocket.org and to my own localhost when I don't use TLS.
The echo_server_both example comes with a server.pem file, and the echo_server_tls example comes with server.pem and dh.pem. I have used the same files that come with the samples, and I have also tried generating and registering my own .pem files using openSSL. In both cases I get this when the client tries to connect:
[2021-06-29 20:51:21] [error] handle_transport_init received error: sslv3 alert certificate unknown
[2021-06-29 20:51:21] [fail] WebSocket Connection [::1]:63346 - "" - 0 asio.ssl:336151574 sslv3 alert certificate unknown
[2021-06-29 20:51:21] [info] asio async_shutdown error: asio.ssl:336462231 (shutdown while in init)
I discovered these errors after I edited handle_init() in tls.hpp, following a suggestion in another site, to look like this:
void handle_init(init_handler callback,lib::asio::error_code const & ec) {
if (ec) {
//m_ec = socket::make_error_code(socket::error::tls_handshake_failed);
m_ec = ec;
} else {
m_ec = lib::error_code();
}
callback(m_ec);
}
This change let the actual openSSL error to show in the console, otherwise it would show a generic "handshake failed" error.
I know I'm not doing what I should with the certificates, but I have no idea where else to look or what to do next. Can anyone here help please? Should I use the .pem files that come with the examples, or should I generate my own? in case I should generate my own, what would be the openSSL command to do that correctly and how do I tell my PC to recognize these as valid so that the server works?
Found the problem: WebSocket++ will not accept a self-signed certificate (the ones you can create directly in your own PC using OpenSSL or the Windows utilities). There is no way around it. You must have a valid, authority-validated and endorsed certificate. You can get such a certificate for free (valid only for 90 days) from https://zerossl.com/. The site has detailed instructions on how to request, obtain and install a certificate. After getting a valid certificate and installing it on my server, everything worked as it should.
I'm trying to communicate in https with a server using WinInet (from the Win32 API).
Here is a very minimalist code :
HINTERNET ses = InternetOpenA("test",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0) ;
HINTERNET con = InternetConnectA(ses,"stackoverflow.com",INTERNET_DEFAULT_HTTPS_PORT,NULL,NULL,INTERNET_SERVICE_HTTP,0,NULL) ;
HINTERNET req = HttpOpenRequestA(con,"GET",NULL,NULL,NULL,NULL,INTERNET_FLAG_SECURE,NULL) ;
HttpSendRequestA(req,NULL,0,NULL,0) ;
DWORD read ;
char str[3000] ;
InternetReadFile(req,reinterpret_cast<void*>(str),sizeof(str)-1,&read);
str[read] = 0 ;
cout << &str[0] << endl ;
As long as I communicate with a "classic" https server, like stackoverflow.com, everything goes well. The problem is when I try to communicate with a server that requests an authentication of the client.
I have 3 .pem files : a certificate and a private key for my client, and a root certificate that authenticates my client certificate (i.e. a certificate chain of length 2).
For information, I can connect my server using this cULR command line :
curl https://my.server --cert Client_cert.pem --key Client_key.pem --cacert Root_cert.pem
This is the proof that it's possible!
Reading the WinInet documentation, I found a page named "Handling Authentication", but it's all about username:password, and there's nothing about certificate.
I found out that I have to use the Crypt32 library : I create a certificate context with CertCreateCertificateContext (using binary data from client_cert.pem) and then pass it using InternetSetOptionA. But then, HttpSendRequestA fails with an error 12157...
I must admit that I would be glad to find a good tutorial or some code sample ! By the way, I don't have a piece of clue about how to insert my private key into that stuff...
Thanks in advance !
I am trying to setup the certificate verification in opensips along with the blink sip client. I followed the tutorial:
https://github.com/antonraharja/book-opensips-101/blob/master/content/3.2.%20SIP%20TLS%20Secure%20Calling.mediawiki
My config look like so:
[opensips.cfg]
disable_tls = no
listen = tls:my_ip:5061
tls_verify_server= 0
tls_verify_client = 1
tls_require_client_certificate = 1
#tls_method = TLSv1
tls_method = SSLv23
tls_certificate = "/usr/local/etc/opensips/tls/server/server-cert.pem"
tls_private_key = "/usr/local/etc/opensips/tls/server/server-privkey.pem"
tls_ca_list = "/usr/local/etc/opensips/tls/server/server-calist.pem"
So i generated the rootCA and the server certificate. Then i took the server-calist.pem added the server-privkey.pem in there (otherwise blink sip client won't load it) and set it in client. I also set the server-calist.pem as a certificate authority in the blink. But when i try to login to my server i get:
Feb 4 21:02:42 user /usr/local/sbin/opensips[28065]: DBG:core:tcp_read_req: Using the global ( per process ) buff
Feb 4 21:02:42 user /usr/local/sbin/opensips[28065]: DBG:core:tls_update_fd: New fd is 17
Feb 4 21:02:42 user /usr/local/sbin/opensips[28065]: ERROR:core:tls_accept: New TLS connection from 130.85.9.114:48253 failed to accept: rejected by client
So i assume that the client doesn't accept the server certificate for some reason, although i have the "Verify server" checkbox turned off in my blink sip client! I think i have the wrong certificate authority file.
./user/user-cert.pem
./user/user-cert_req.pem
./user/user-privkey.pem
./user/user-calist.pem <- this 4 are for using opensips as a client i think
./rootCA/certs/01.pem
./rootCA/private/cakey.pem
./rootCA/cacert.pem
./server/server-privkey.pem
./server/server-calist.pem
./server/server-cert.pem
./server/server-cert_req.pem
./calist.pem
Can anybody help, did i do something wrong i the config or did i use the wrong certificate chain? What certificate exactly should be used by the client as a client cert, and ca authority cert?
Allright, i'm still not sure if it is working or not, because the authorization behaviour became weird, but after it's hanging for 5-6 minutes i get the success authorization, so this is a solution:
Generate rootCA:
opensipsctl tls rootCA
then edit server.conf file in your tls opensips folder and set the commonName = xxx.xxx.xxx.xxx where xxx.xxx.xxx.xxx is your server ip address. Other variables can be edited in any way. Generate the certificates signed by CA
opensipsctl tls userCERT server
This will produce 4 files. Download the server-calist.pem, server-cert.pem, server-privkey.pem. Open the server-privkey.pem, copy it's content and paste in the file server-cert.pem, before the actual certificate. If you are using blink, the produced server-cert.pem goes in the preferences->account->advanced. And server-calist.pem goes into the preferences->advanced. After that restart blink and after 5-6 minutes your account is gonna be logged in. But i'v observed a weird behaviour, if you run another copy of blink and try to log into the other existing account after your logged from the first one with the certificates, you can log in from other account without providing the certificates. So i don't know, but i think it's working.
P.S. I asked about the certificates in the opensips mailing list, but i guess they found my question too lame, so i didn't get the response. If you have the same problem and got better results or an answer from opensips support let me know please.
I'm trying to figure out how to use the self compiled OpenSSL API to load an existing X.509 certificate (.crt) which I have included in Xcode's project structure.
I need a X509 object (from OpenSSL x509.h) which should be created/loaded from an existing file. Including the header works fine but I really can't find a way to load an existing certificate... There are sooo many methods in the x509.h but no sufficient documentation.
Thanks,
Chris
If you've read the character data into a char* s, something like
BIO* bio = BIO_new_mem_buf((void*)s, -1);
X509* cert = 0;
PEM_read_bio_X509(bio, &cert, 0, NULL);
...
X509_free(cert);
BIO_free(bio);