Превратите простой сокет в сокет 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 внутри приложения, OpenSSL довольно прост, если вы понимаете, как должен работать SSL / TLS. Если вам нужна альтернатива, попробуйте yaSSL или gnuTLS.
Borealid 08
3
Дайте определение «легкий путь». OpenSSl - это стандарт для программистов на C. Если у вас возникли трудности с этим, спросите об этом.
Marquis of Lorne
Отметьте это Введение в программирование OpenSSL (Часть I) . Часть II для меня слишком сложна и сложна. Но часть 2 стоит взглянуть.
Рик
Также проверьте Безопасное программирование с помощью OpenSSL API . Но я только что слышал мнения о том, насколько плох Openssl и другие альтернативы, которые стоит попробовать.
Рик
Другой вариант - использовать внешний инструмент-оболочку SSL, например stunnel, stunnel4пакет находится в дистрибутиве на основе 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.

CaptainBli
источник
9
не так "просто", как я думал, но наконец (слава богу!) я вижу код. Это кроссплатформенный или только для unix / unix-подобных систем?
juliomalegria
3
Я использовал похожий код на нескольких платформах: arm, linux и windows.
CaptainBli
2
Однако последнее ifневерно. Должно быть if (ssl_err <= 0) {только тогда это ошибка. SSL_accept()возвращается 1в случае успеха, 0в случае «контролируемого отказа» и -1«фатального отказа». См. Страницу руководства.
Jite
2
Кроме того, шифры DH не будут работать, если SSL_CTX_set_tmp_dh[_callback]()не будут вызваны. Только что обнаружил на собственном опыте, что без него не будут работать NULL-шифры, генерируя предупреждение номер 40.
Роман Дмитриенко
5
@DevNull Указывает, SSLv23_server_method()что сервер понимает SSLv2 и v3 и теперь устарел. Для поддержки TLS 1.1 и 1.2 замените этот метод на TLS_server_method(). источник
ezPaint
17

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

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

СмелыйНовыйВалюта
источник
11
Это практический ответ, но на самом деле он не отвечает на вопрос.
Швейцарский
4
STUD был заброшен в 2016 году. В readme рекомендуется: github.com/varnish/hitch
Charles
7

Для таких, как я:

Когда-то был пример в источнике 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

18446744073709551615
источник
-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;
}
Fanex
источник
Пожалуйста, включите решение прямо в сообщение SO.
Maciej Jureczko