📜 ⬆️ ⬇️

The easiest cross-platform server with ssl support

Not long ago, I was faced with the task: to write a cross-platform server for processing requests via the ssl protocol. Before that, I wrote a server for plain, unencrypted protocols, but I ran into ssl for the first time.
A cursory review of the Internet showed that the best solution would not be cycling, but using the OpenSSL library.
In this article I don’t want to consider installing OpenSSL on Linux and Windows, I’d just note that for Windows this process turned out to be non-trivial. And I want to tell you about how I managed to compile in Visual Studio an example of a simple server that is part of the OpenSSL sources.
To an inexperienced reader, it may seem: “what is special about this - he created the project, included the ready source code in it, launched it” ... But first things first.

For me, as a programmer, it is easier to tell actions in steps:

1. Create an experiment directory:
Let it be for example C: \ testssl
')
2. Download the OpenSSL source code.
Let this code be stored in the directory C: \ openssl-1.0.1c
3. Compile OpenSSL
After compilation you will have a directory with library and header files. Copy this directory to our test. This should result in the following structure of files and directories:
C: \ testssl
C: \ testssl \ openssl
From: \ testssl \ openssl \ bin
C: \ testssl \ openssl \ bin \ openssl.exe
C: \ testssl \ openssl \ include
C: \ testssl \ openssl \ include \ openssl
C: \ testssl \ openssl \ include \ openssl \ aes.h
..... (there are many header files)
C: \ testssl \ openssl \ include \ openssl \ x509v3.h
C: \ testssl \ openssl \ lib
From: \ testssl \ openssl \ lib \ libeay32.lib
From: \ testssl \ openssl \ lib \ ssleay32.lib
C: \ testssl \ openssl \ ssl
From: \ testssl \ openssl \ ssl \ openssl

4. Copy the required example from C: \ openssl-1.0.1c \ demos \ ssl \ serv.cpp to C: \ testssl \ serv.cpp

5. For the example, you will need a file with a secret key. This file can also be taken from source.
Copy it from C: \ openssl-1.0.1c \ certs \ demo \ ca-cert.pem in : \ testssl \ ca-cert.pem

5. Create an empty console project in Visual Studio and add the serv.cpp file to it.
6. In the project properties, add the path for the headers: : \ testssl \ openssl \ include and the path for the libraries: : \ testssl \ openssl \ lib . As well as the libraries themselves libeay32.lib, ssleay32.lib

7. Now in the code we fix

#define CERTF HOME "foo-cert.pem" #define KEYF HOME "foo-cert.pem" 


on
 #define CERTF HOME "ca-cert.pem" #define KEYF HOME "ca-cert.pem 


8. It would seem that this is all, but of course the code will not compile. The fact is that in Windows and Linux you need to include different standard header files.

Need to fix
 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <memory.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <openssl/rsa.h> /* SSLeay stuff */ #include <openssl/crypto.h> #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/ssl.h> #include <openssl/err.h> 


on
 #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <errno.h> #include <sys/types.h> #ifndef WIN32 #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #else #include <io.h> #include <Winsock2.h> #pragma comment(lib, "ws2_32.lib") #endif #include <openssl/rsa.h> /* SSLeay stuff */ #include <openssl/crypto.h> #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/ssl.h> #include <openssl/err.h> 


As you can see, for Windows you need to include the “Winsock2.h” file, as well as just in case the socket library.

9. But that's not all! If you now try to compile the project, you will get errors:
error C2440: '=': cannot convert from 'const SSL_METHOD *' to 'SSL_METHOD *'
error C2664: 'accept': cannot convert parameter 3 from 'size_t *' to 'int *'

These errors are easily found and corrected, but if you want to be croscoplatformal, then you need to fix it carefully:

For the first error you need
  meth = SSLv23_server_method(); 


fix on

 #ifdef WIN32 const SSL_METHOD *meth = SSLv23_server_method(); #else SSL_METHOD *meth = SSLv23_server_method(); #endif 


For the second error you need
  sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len); 


fix on

 #ifdef WIN32 sd = accept (listen_sd, (struct sockaddr*) &sa_cli, (int *)&client_len); #else sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len); #endif 


10. Now the code will compile and run, but will generate an error in the line
“Listen_sd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR (listen_sd, "socket"); "
Yes. In Windows, to work with sockets, you must first call the WSAStartup () function!
Add it to the beginning of the program:
 void main () { int err; int listen_sd; int sd; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; size_t client_len; SSL_CTX* ctx; SSL* ssl; X509* client_cert; char* str; char buf [4096]; #ifdef WIN32 WSADATA wsaData; if ( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != 0 ) { printf("Could not to find usable WinSock in WSAStartup\n"); return; } #endif 


11. We start the program, Windows asks for permissions so that the application can open the port. Allow.
Application reaches line
 sd = accept (listen_sd, (struct sockaddr*) &sa_cli, (int *)&client_len); 

and freezes.
That's right, our server is waiting for someone to connect to it.
At this stage, you can connect from the command line: "telnet localhost 1111". As soon as the connection is made, the program will continue until line
 close (listen_sd); 

On this line, Visual Studio will generate an incomprehensible error.
But if you figure it out, it turns out that in Windows, sockets are closed with another function: “closesocket ()”.
To avoid mistakes, we change everywhere close to closesocket, and for cross-platform add code:
 #ifndef WIN32 #define closesocket close #endif 


12. Now the application has started and worked to the line
 err = SSL_accept (ssl); CHK_SSL(err); 

Here it hung again, apparently expecting ssl protocol messaging from the client.
I personally do not know how to exchange these messages manually with a telnet. But to test the program to the end, you can use a regular browser!

13. To test the functionality of our server, we launch it, and instead of the command line, we launch a browser.
In the address bar of the browser type: localhost:1111
The browser will warn about the unsafe certificate. Need to take a risk. However, while we are communicating with the browser, the server may fail again. This is normal, run it again.

14. Now, when the server is running, and the browser remembers that we trust this server, our program will finally work to the end and will receive the letter “G” from the browser (the beginning of the request “GET”), via an encrypted connection!

15. This could be finished, but I decided to compile the resulting file on Linux for the purity of the experiment. It turned out that there are not without surprises.
At compile time I get an error:
serv.cpp: 51: error: ':: main' must return 'int'

This is how it is. It turns out an example from OpenSSL sources is not compiled not only in Windows, but also in Linux.
Of course, I corrected “void main ()” to “int main ()” and everywhere instead of “return” I wrote “return 0”, but the sediment remained.

And if it is suddenly interesting, it is compiled in Linux with the following line: "g ++ -L / usr / lib -lssl -lcrypto serv.cpp".

PS: this is my first post on Habré, so I apologize to the community, if it turned out long and confusing. The project for Visual Studio 2012 is available in the archive: e0.3s3s.org

PPS: Wrote the continuation of this article: habrahabr.ru/post/211661

Source: https://habr.com/ru/post/211474/


All Articles