Поверните простой сокет в сокет 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 в свой проект, но я не могу найти простой способ реализовать то, что хочу.

Ответ 1

Есть несколько шагов при использовании 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.

Ответ 2

OpenSSL довольно сложно. Легко случайно выбросить всю вашу безопасность, не делая правильные переговоры. (Черт, я был лично укушен ошибкой, где завиток не читал предупреждения OpenSSL точно так же и не мог разговаривать с некоторыми сайтами.)

Если вы действительно хотите быстро и просто, поставьте stud перед своей программой, позвоните в один день. Наличие SSL в другом процессе не замедлит вас: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html

Ответ 3

Для других, как я:

Однажды был пример в источнике SSL в каталоге demos/ssl/ с примером кода в C++. Теперь он доступен только через историю: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Вам, вероятно, придется найти рабочую версию, я первоначально опубликовал этот ответ 6 ноября 2015 года. И мне пришлось редактировать исходный код - не так много.

Сертификаты:.pem в demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps

Ответ 4

Код, который помогает конвертировать обычный сокет в защищенный сокет, где чаты защищены с помощью ssl. send и recv вызовы в сокет будут заменены вызовами ssl_read и ssl_write: Больше на: http://www.writeulearn.com/secure-ssl-socket/

Ответ 5

Здесь мой пример потоков сервера 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;
}