単純なソケットをSSLソケットに変える


115

ソケット(「クライアント」と「サーバー」)を使用する単純なCプログラムを作成しました。(UNIX / Linuxの使用)

サーバー側は単にソケットを作成します:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

そして、それをsockaddrにバインドします。

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

そして聞いて(そして受け入れて読んで):

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
read(newsockfd,buffer,255);

クライアントはソケットを作成してから、ソケットに書き込みます。

今、私はこの単純な接続をSSL接続に変換したいと思います。

OpenSSLをプロジェクトに追加しようとしましたが、必要なものを実装する簡単な方法が見つかりません。


特にSSLではなく「安全な接続」を探している場合は、アプリケーションの外部にあるproxychains.sourceforge.netのようなものを見て、SSH接続を介してトラフィックを送信するように設定できます。アプリケーション内SSLに関しては、SSL / TLSがどのように機能するかを理解していれば、OpenSSLは非常に簡単です。別の方法が必要な場合は、yaSSLまたはgnuTLSを試してください。
Borealid、2011年

3
「簡単な方法」を定義します。OpenSSlはCプログラマの標準です。あなたがそれで問題を抱えているなら、あなたはそれについて尋ねるべきです。
ローンの侯爵2013

こちらのOpenSSLプログラミング入門(Par t I)をチェックしてください。パートIIは高度すぎるため、私には困難です。しかし、part2は一見の価値があります。
リック、

OpenSSL APIを使用したセキュアなプログラミングも確認してください。しかし、Opensslがいかに悪いか、他に試してみる価値のある選択肢についての意見を聞いたところです。
リック、

別のオプションは、次のような外部のSSLラッパーツールを使用することでstunnelstunnel4パッケージはDebianベースのディストリビューションであり、それを使用するのは簡単です。サーバーに適切なSSLサポートを追加する場合と比較していくつかの制限がありますが、迅速な解決策としては良い場合があります。私はstunnelが好きです。UNIXソフトウェアツールのアプローチに適合するようです。
サムワトキンス

回答:


150

OpenSSLを使用する場合、いくつかの手順があります。秘密鍵を含む証明書を含めることができるSSL証明書を作成する必要があります。証明書の正確な場所を指定してください(この例ではルートにあります)。たくさんの良いチュートリアルがあります。

以下が含まれます:

#include <openssl/applink.c>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

OpenSSLを初期化する必要があります。

void InitializeSSL()
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void DestroySSL()
{
    ERR_free_strings();
    EVP_cleanup();
}

void ShutdownSSL()
{
    SSL_shutdown(cSSL);
    SSL_free(cSSL);
}

次に、機能の大部分について説明します。接続にwhileループを追加することもできます。

int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;

InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0)
{
    //Log and Error
    return;
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = serv_addr;
saiServerAddress.sin_port = htons(aPortNumber);

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

sslctx = SSL_CTX_new( SSLv23_server_method());
SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
int use_cert = SSL_CTX_use_certificate_file(sslctx, "/serverCertificate.pem" , SSL_FILETYPE_PEM);

int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "/serverCertificate.pem", SSL_FILETYPE_PEM);

cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//Here is the SSL Accept portion.  Now all reads and writes must use SSL
ssl_err = SSL_accept(cSSL);
if(ssl_err <= 0)
{
    //Error occurred, log and close down ssl
    ShutdownSSL();
}

その後、以下を使用して読み取りまたは書き込みができます。

SSL_read(cSSL, (char *)charBuffer, nBytesToRead);
SSL_write(cSSL, "Hi :3\n", 6);

更新 ザ・はSSL_CTX_new最高のは、セキュリティの新しいバージョンをサポートし、代わりにするために、あなたのニーズに合っていることTLS方式と呼ばれるべきですSSLv23_server_method()。参照: OpenSSL SSL_CTX_new説明

TLS_method()、TLS_server_method()、TLS_client_method()。 これらは、汎用のバージョンに柔軟な SSL / TLSメソッドです。使用される実際のプロトコルバージョンは、クライアントとサーバーによって相互にサポートされる最高バージョンにネゴシエートされます。サポートされるプロトコルは、SSLv3、TLSv1、TLSv1.1、TLSv1.2、およびTLSv1.3です。


9
思ったほど単純ではありませんが、ついに(神に感謝します!)いくつかのコードが表示されます。これはクロスプラットフォームですか、それともunix / unixのようなシステムですか?
juliomalegria 2013年

3
複数のプラットフォーム(arm、linux、windows)で同様のコードを使用しました。
CaptainBli 2013

2
最後ifは間違っています。それはそれif (ssl_err <= 0) {だけでエラーになるはずです。成功時、「制御された失敗時」、「致命的な失敗時」にSSL_accept()戻ります。manページを参照してください。10-1
Jite、2014

2
また、DH暗号SSL_CTX_set_tmp_dh[_callback]()は、呼び出されない場合は機能しません。ただ、aNULL暗号アラート番号40をそれなしではない仕事、生産することを、ハードな方法を発見
ローマDmitrienkoを

5
@DevNull SSLv23_server_method()サーバーがSSLv2とv3を理解しており、現在は推奨されていないことを示します。TLS 1.1および1.2をサポートするには、そのメソッドをに置き換え TLS_server_method()ます。ソース
ezPaint 2016年

17

OpenSSLは非常に困難です。ネゴシエーションを正確に行わないと、誤ってすべてのセキュリティを破棄してしまう可能性があります。(私は個人的に、curlがOpenSSLアラートを正確に読み取らず、一部のサイトと通信できなかったバグに個人的に噛まれました。)

本当にすばやく簡単にしたい場合は、プログラムの前にスタッドを置いて、1日と呼びます。別のプロセスでSSLを使用しても、速度が低下することはありません。http//vincent.bernat.im/en/blog/2011-ssl-benchmark.html


11
これは実用的な答えですが、実際に質問に答えることはできません。
スイスの

4
STUDは2016年に廃止されました。Readmeは次の
Charles

7

私のような他の人のために:

かつて、demos/ssl/C ++のサンプルコードを含むディレクトリのSSLソースにサンプルがありました。現在は、履歴経由でのみ利用できます:https : //github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

おそらく、動作するバージョンを見つける必要があります。私は2015年11月6日にこの回答を最初に投稿しました。ソースを編集する必要がありましたが、それほど多くはありませんでした。

証明書:.pem in demos/certs/apps/https : //github.com/openssl/openssl/tree/master/demos/certs/apps


-1

ここに私の例のsslソケットサーバースレッド(複数接続)https://github.com/breakermind/CppLinux/blob/master/QtSslServerThreads/breakermindsslserver.cpp

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <iostream>

#include <breakermindsslserver.h>

using namespace std;

int main(int argc, char *argv[])
{
    BreakermindSslServer boom;
    boom.Start(123,"/home/user/c++/qt/BreakermindServer/certificate.crt", "/home/user/c++/qt/BreakermindServer/private.key");
    return 0;
}

SOポストに直接ソリューションを含めてください。
Maciej Jureczko
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.