web-dev-qa-db-ja.com

単純なソケットをSSLソケットに変換します

ソケット(「クライアント」と「サーバー」)を使用する単純な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 を追加しようとしましたが、必要なものを実装する簡単な方法が見つかりません。

104
David Mape

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);

UpdateSSL_CTX_newは、SSLv23_server_method()ではなく、新しいバージョンのセキュリティをサポートするために、ニーズに最適なTLSメソッドで呼び出す必要があります。参照: OpenSSL SSL_CTX_new description

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

135
CaptainBli

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

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

16

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

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

おそらく作業バージョンを見つける必要があります。最初にこの回答を2015年11月6日に投稿しました。そして、ソースを編集する必要がありました。

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

ここに私の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;
}
0
Fanex