SSLをサポートする最もシンプルなクロスプラットフォームサーバー

少し前まで、私はタスクに直面していました:sslプロトコルを使用してリクエストを処理するためのクロスプラットフォームサーバーを書くこと。 その前に、暗号化されていない通常のプロトコル用のサーバーを作成しましたが、最初にsslに遭遇しました。
インターネットの簡単なレビューにより、最良の解決策は自転車の製造ではなく、OpenSSLライブラリの使用であることが示されました。
この記事では、LinuxおよびWindowsにOpenSSLをインストールするプロセスを検討したくありません。Windowsの場合、このプロセスは簡単ではないことに注意してください。 そして、OpenSSLソースコードの一部である単純なサーバーの例をVisual Studioでどのようにコンパイルしたかについてお話したいと思います。
経験の浅い読者には、「特別なこと-プロジェクトを作成し、既成のソースを含めて、それを開始した」ように思えるかもしれません...しかし、最初にまず最初に。

プログラマーとして、ステップごとにステップを説明する方が簡単です。

1.実験用のディレクトリを作成します。
たとえば、 C:\ testsslとします。

2. OpenSSLソースコードをダウンロードする
このコードを、たとえばディレクトリC:\ openssl-1.0.1cに保存します。
3. OpenSSLのコンパイル
コンパイル後、ライブラリとヘッダーファイルのあるディレクトリが作成されます。 このディレクトリをテストディレクトリにコピーします。 結果は、次のファイルとディレクトリの構造になります。
C:\ testssl
C:\ testssl \ openssl
C:\ 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
..... (ヘッダーファイルがたくさんあります)
C:\ testssl \ openssl \ include \ openssl \ x509v3.h
C:\ testssl \ openssl \ lib
C:\ testssl \ openssl \ lib \ libeay32.lib
C:\ testssl \ openssl \ lib \ ssleay32.lib
C:\ testssl \ openssl \ ssl
C:\ testssl \ openssl \ ssl \ openssl

4. C:\ openssl-1.0.1c \ demos \ ssl \ serv.cppから目的の例をC:\ testssl \ serv.cppにコピーします。

5.例が機能するためには、秘密鍵を含むファイルが必要です。 このファイルはソースから取得することもできます。
C:\ openssl-1.0.1c \ certs \ demo \ ca-cert.pemからC:\ testssl \ ca-cert.pemにコピーします。

5. Visual Studioで空のコンソールプロジェクトを作成し、serv.cppファイルを追加します。
6.プロジェクトのプロパティで、ヘッダーのパスC:\ testssl \ openssl \ includeとライブラリのパスC:\ testssl \ openssl \ libを追加します。 また、 libeay32.lib、ssleay32.libライブラリ自体も

7.ここで、コードを修正します

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



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


8.これですべてのように見えますが、もちろんコードはコンパイルされません。 実際、WindowsとLinuxでは、異なる標準ヘッダーファイルを含める必要があります。

修正が必要
 #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> 



 #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> 


ご覧のとおり、Windowsの場合は、「Winsock2.h」ファイルと、念のためソケットライブラリを含める必要があります。

9.しかし、それだけではありません! ここでプロジェクトをコンパイルしようとすると、エラーが生成されます。
エラーC2440:「=」:「const SSL_METHOD *」から「SSL_METHOD *」に変換できません
エラーC2664: 'accept':パラメーター3を 'size_t *'から 'int *'に変換できません

これらのエラーは簡単に見つけて修正できますが、クロスプラットフォームが必要な場合は、慎重に修正する必要があります。

あなたが必要とする最初の間違いのために
  meth = SSLv23_server_method(); 


修正する

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


2番目のエラーには、次のものが必要です。
  sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len); 


修正する

 #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.これでコードがコンパイルされて実行されますが、次の行にエラーがスローされます
「Listen_sd = socket(AF_INET、SOCK_STREAM、0); CHK_ERR(listen_sd、「ソケット」);”
はい Windowsでソケットを操作するには、最初にWSAStartup()関数を呼び出す必要があります!
プログラムの先頭に追加します:
 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.プログラムを実行すると、アプリケーションがポートを開くことができるようにWindowsが許可を求めます。 許可された。
アプリケーションはラインに到達します
 sd = accept (listen_sd, (struct sockaddr*) &sa_cli, (int *)&client_len); 

そしてフリーズします。
そうです、サーバーは誰かが接続するのを待っています。
この時点で、コマンドライン「telnet localhost 1111」から接続できます。 接続が発生するとすぐに、プログラムは引き続き実行されます
 close (listen_sd); 

Visual Studioは、この行に不可解なエラーを表示します。
しかし、見てみると、Windowsソケットは別の関数「closesocket()」で閉じられていることがわかります。
エラーを回避するために、closesocketに近いすべての場所を変更し、クロスプラットフォームのコードを追加します。
 #ifndef WIN32 #define closesocket close #endif 


12.これで、アプリケーションが開始され、行に実行されました
 err = SSL_accept (ssl); CHK_SSL(err); 

ここで再びハングしました。どうやらSSLメッセージングクライアントが必要でした。
これらのメッセージを手動でtelnetと交換する方法は、個人的にはわかりません。 しかし、プログラムの動作を最後まで確認するには、通常のブラウザを使用できます!

13.サーバーの状態をテストするには、サーバーを実行し、コマンドラインの代わりにブラウザーを起動します。
ブラウザのアドレスバーに次のように入力します。 localhost:1111
ブラウザは安全でない証明書を警告します。 リスクを取る必要があります。 ただし、ブラウザとの通信中に、サーバーが再び失敗する場合があります。 これは正常な動作です。もう一度実行してください。

14.サーバーが実行され、ブラウザーがこのサーバーを信頼していることを記憶しているため、プログラムは最終的に暗号化された接続を介してブラウザーから「G」という文字(「GET」リクエストの先頭)を受け取ります!

15.これで終わりますが、実験の純度のために、結果ファイルをLinuxでコンパイルすることにしました。 いくつかの驚きがあったことが判明しました。
コンパイル段階で、エラーが発生しました。
serv.cpp:51:エラー: ':: main'は 'int'を返す必要があります

ここにある。 ソースOpenSSLがWindowsだけでなくLinuxでもコンパイルされないことがわかります。
もちろん、「void main()」を「int main()」に修正し、「return」の代わりに「return 0」と書きましたが、沈殿物は残りました。

そして、それが突然おもしろければ、「g ++ -L / usr / lib -lssl -lcrypto serv.cpp」という行でLinuxでコンパイルします。

PS:これはハブに関する私の最初の投稿です。そのため、長くて混乱していることがわかった場合はコミュニティに謝罪します。 Visual Studio 2012のプロジェクトは、アーカイブe0.3s3s.orgで入手できます。

PPP:この記事の続きを書きました: habrahabr.ru/post/211661

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


All Articles