Verwandeln Sie einen einfachen Socket in einen SSL-Socket

115

Ich habe einfache C-Programme geschrieben, die Sockets verwenden ('Client' und 'Server'). (UNIX / Linux-Verwendung)

Die Serverseite erstellt einfach einen Socket:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

Und bindet es dann an sockaddr:

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

Und hört zu (und akzeptiert und liest):

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

Der Client erstellt den Socket und schreibt darauf.

Jetzt möchte ich diese einfache Verbindung auf einfachste, idyllischste, ordentlichste und schnellste Weise in eine SSL-Verbindung umwandeln.

Ich habe versucht, OpenSSL zu meinem Projekt hinzuzufügen , aber ich kann keinen einfachen Weg finden, um das zu implementieren, was ich will.

David Mape
quelle
Wenn Sie eher nach einer "sicheren Verbindung" als nach SSL suchen, können Sie sich beispielsweise proxychains.sourceforge.net ansehen, das sich außerhalb Ihrer Anwendung befindet, und dies so einrichten, dass Datenverkehr über eine SSH-Verbindung gesendet wird . In Bezug auf anwendungsinternes SSL ist OpenSSL ziemlich einfach, wenn Sie verstehen, wie SSL / TLS funktionieren soll. Wenn Sie eine Alternative wünschen, versuchen Sie es mit yaSSL oder gnuTLS.
Borealid
3
Definieren Sie 'einfachen Weg'. OpenSSl ist der Standard für C-Programmierer. Wenn Sie Schwierigkeiten damit haben, sollten Sie danach fragen.
Marquis von Lorne
Überprüfen Sie diese Eine Einführung in die OpenSSL-Programmierung (Teil I) . Teil II ist zu weit fortgeschritten und schwierig für mich. Aber Teil 2 ist einen Blick wert.
Rick
Überprüfen Sie auch die sichere Programmierung mit der OpenSSL-API . Aber ich habe gerade Meinungen darüber gehört, wie schlecht Openssl ist und andere Alternativen, die einen Versuch wert sind.
Rick
Eine andere Option ist die Verwendung eines externen SSL-Wrapper-Tools, z. B. stunneldas stunnel4Paket befindet sich in Debian-basierten Distributionen und ist einfach zu verwenden. Es gibt einige Einschränkungen im Vergleich zum Hinzufügen einer ordnungsgemäßen SSL-Unterstützung auf Ihrem Server, aber dies kann für eine schnelle Lösung hilfreich sein. Ich mag Stunnel, weil es zum Ansatz der UNIX-Softwaretools zu passen scheint.
Sam Watkins

Antworten:

150

Bei Verwendung von OpenSSL gibt es mehrere Schritte. Sie müssen ein SSL-Zertifikat erstellen lassen, das das Zertifikat mit dem privaten Schlüssel enthalten kann. Geben Sie unbedingt den genauen Speicherort des Zertifikats an (in diesem Beispiel befindet es sich im Stammverzeichnis). Es gibt viele gute Tutorials.

Einige beinhalten:

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

Sie müssen OpenSSL initialisieren:

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

Nun zum Großteil der Funktionalität. Möglicherweise möchten Sie eine while-Schleife für Verbindungen hinzufügen.

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

Sie können dann lesen oder schreiben mit:

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

Update Das SSL_CTX_newsollte mit der TLS-Methode aufgerufen werden, die Ihren Anforderungen am besten entspricht, um die neueren Sicherheitsversionen zu unterstützen SSLv23_server_method(). Siehe: OpenSSL SSL_CTX_neue Beschreibung

TLS_method (), TLS_server_method (), TLS_client_method (). Dies sind die universellen Versionen, die flexibel sind SSL / TLS-Methoden. Die tatsächlich verwendete Protokollversion wird mit der höchsten Version ausgehandelt, die vom Client und vom Server gegenseitig unterstützt wird. Die unterstützten Protokolle sind SSLv3, TLSv1, TLSv1.1, TLSv1.2 und TLSv1.3.

CaptainBli
quelle
9
nicht so "einfach" wie ich dachte, aber schließlich (Gott sei Dank!) sehe ich einen Code. Ist das plattformübergreifend oder nur für Unix / Unix-ähnliche Systeme?
Juliomalegria
3
Ich habe ähnlichen Code auf mehreren Plattformen verwendet: Arm, Linux und Windows.
CaptainBli
2
Letzteres ifist allerdings falsch. Es sollte if (ssl_err <= 0) {nur dann sein, dass es ein Fehler ist. SSL_accept()kehrt 1bei Erfolg, 0bei "kontrolliertem Fehler" und -1bei "tödlichem Fehler" zurück. Siehe Manpage.
Jite
2
Außerdem funktionieren DH-Chiffren nicht, wenn sie SSL_CTX_set_tmp_dh[_callback]()nicht aufgerufen werden. Habe gerade den harten Weg entdeckt, dass aNULL-Chiffren ohne sie nicht funktionieren und die Alarmnummer 40 erzeugen.
Roman Dmitrienko
5
@DevNull Gibt an SSLv23_server_method(), dass der Server SSLv2 und v3 versteht und jetzt veraltet ist. Um TLS 1.1 und 1.2 zu unterstützen, ersetzen Sie diese Methode durch TLS_server_method(). Quelle
ezPaint
17

OpenSSL ist ziemlich schwierig. Es ist leicht, versehentlich Ihre gesamte Sicherheit wegzuwerfen, wenn Sie nicht genau richtig verhandeln. (Heck, ich bin persönlich von einem Fehler gebissen worden, bei dem Curl die OpenSSL-Warnungen nicht genau richtig gelesen hat und mit einigen Websites nicht sprechen konnte.)

Wenn Sie wirklich schnell und einfach wollen, stellen Sie Stud auf Ihr Programm und nennen Sie es einen Tag. Wenn Sie SSL in einem anderen Prozess verwenden, werden Sie nicht langsamer: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html

BraveNewCurrency
quelle
11
Dies ist eine praktische Antwort, aber sie beantwortet die Frage nicht wirklich.
Schweizer
4
STUD wurde 2016 aufgegeben. Die Readme-Datei empfiehlt: github.com/varnish/hitch
Charles
7

Für andere wie mich:

Es gab einmal ein Beispiel in der SSL-Quelle im Verzeichnis demos/ssl/mit Beispielcode in C ++. Jetzt ist es nur über die Historie verfügbar: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Sie müssen wahrscheinlich eine funktionierende Version finden, ich habe diese Antwort ursprünglich am 6. November 2015 gepostet. Und ich musste die Quelle bearbeiten - nicht viel.

Zertifikate: .pem in demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps

18446744073709551615
quelle
-1

Hier mein Beispiel ssl Socket Server Threads (Mehrfachverbindung) 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
quelle
Bitte fügen Sie die Lösung direkt in Ihren SO-Beitrag ein.
Maciej Jureczko