Transformez un simple socket en socket SSL

115

J'ai écrit des programmes C simples, qui utilisent des sockets («client» et «serveur»). (Utilisation UNIX / Linux)

Le côté serveur crée simplement un socket:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

Et puis le lie à sockaddr:

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

Et écoute (et accepte et lit):

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

Le client crée le socket, puis y écrit.

Maintenant, je veux convertir cette simple connexion en une connexion SSL, de la manière la plus simple, la plus idyllique, la plus soignée et la plus rapide.

J'ai essayé d'ajouter OpenSSL à mon projet, mais je ne trouve pas de moyen simple de mettre en œuvre ce que je veux.

David Mape
la source
Si vous recherchez "une connexion sécurisée" plutôt que SSL en particulier, vous pouvez regarder quelque chose comme proxychains.sourceforge.net qui réside en dehors de votre application, et configurer cela pour envoyer du trafic via une connexion SSH. En ce qui concerne le SSL intégré à l'application, OpenSSL est assez simple si vous comprenez comment SSL / TLS est censé fonctionner. Si vous voulez une alternative, essayez yaSSL ou gnuTLS.
Borealid
3
Définissez le «moyen facile». OpenSSl est la norme pour les programmeurs C. Si vous rencontrez des difficultés, vous devriez poser des questions à ce sujet.
Marquis of Lorne
Cochez celle-ci Une introduction à la programmation OpenSSL (Partie I) . La partie II est trop avancée et difficile pour moi. Mais part2 vaut le coup d'œil.
Rick
Vérifiez également la programmation sécurisée avec l'API OpenSSL . Mais je viens d'entendre des opinions sur la mauvaise qualité d'OpenSl et d'autres alternatives qui valent la peine d'être essayées.
Rick
Une autre option consiste à utiliser un outil d'encapsulation SSL externe tel que stunnel, le stunnel4paquet est dans des distributions basées sur Debian et il est facile à utiliser. Il existe certaines limitations par rapport à l'ajout d'un support SSL approprié sur votre serveur, mais cela peut être bon pour une solution rapide. J'aime stunnel car il semble correspondre à l'approche des outils logiciels UNIX.
Sam Watkins

Réponses:

150

Il y a plusieurs étapes lors de l'utilisation d'OpenSSL. Vous devez avoir un certificat SSL qui peut contenir le certificat avec la clé privée, assurez-vous de spécifier l'emplacement exact du certificat (cet exemple l'a à la racine). Il existe de nombreux didacticiels de qualité.

Certains comprennent:

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

Vous devrez initialiser 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);
}

Maintenant, pour l'essentiel des fonctionnalités. Vous pouvez ajouter une boucle while sur les connexions.

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

Vous pouvez alors lire ou écrire en utilisant:

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

Update Le SSL_CTX_newdoit être appelé avec la méthode TLS qui correspond le mieux à vos besoins afin de prendre en charge les nouvelles versions de sécurité, au lieu de SSLv23_server_method(). Voir: Description d'OpenSSL SSL_CTX_new

TLS_method (), TLS_server_method (), TLS_client_method (). Il s'agit des méthodes SSL / TLS polyvalentes et flexibles . La version réelle du protocole utilisée sera négociée à la version la plus élevée mutuellement prise en charge par le client et le serveur. Les protocoles pris en charge sont SSLv3, TLSv1, TLSv1.1, TLSv1.2 et TLSv1.3.

CaptainBli
la source
9
pas si "simple" que je le pensais, mais finalement (merci mon Dieu!) je vois du code. Est-ce multiplateforme ou juste pour les systèmes de type Unix / Unix?
juliomalegria
3
J'ai utilisé un code similaire sur plusieurs plates-formes: arm, linux et windows.
CaptainBli
2
Le dernier ifest faux cependant. Ce ne devrait être qu'alors if (ssl_err <= 0) {que c'est une erreur. SSL_accept()retourne 1sur succès, 0sur «échec contrôlé» et -1sur «échec fatal». Voir la page de manuel.
Jite
2
De plus, les chiffrements DH ne fonctionneront pas s'ils SSL_CTX_set_tmp_dh[_callback]()ne sont pas appelés. Je viens de découvrir à la dure qu'un chiffrement NULL ne fonctionnera pas sans lui, produisant le numéro d'alerte 40.
Roman Dmitrienko
5
@DevNull Indique SSLv23_server_method()que le serveur comprend SSLv2 et v3 et est désormais obsolète. Pour prendre en charge TLS 1.1 et 1.2, remplacez cette méthode par TLS_server_method(). source
ezPaint
17

OpenSSL est assez difficile. Il est facile de jeter accidentellement toute votre sécurité en ne négociant pas exactement comme il faut. (Heck, j'ai été personnellement mordu par un bug où curl ne lisait pas exactement les alertes OpenSSL et ne pouvait pas parler à certains sites.)

Si vous voulez vraiment rapide et simple, placez le goujon devant votre programme et appelez-le par jour. Avoir SSL dans un processus différent ne vous ralentira pas: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html

BraveNewCurrency
la source
11
C'est une réponse pratique, mais elle ne répond pas vraiment à la question.
Suisse
4
STUD a été abandonné en 2016. Le readme recommande: github.com/varnish/hitch
Charles
7

Pour d'autres comme moi:

Il y avait une fois un exemple dans la source SSL dans le répertoire demos/ssl/avec un exemple de code en C ++. Désormais, il n'est disponible que via l'historique: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Vous devrez probablement trouver une version fonctionnelle, j'ai initialement publié cette réponse le 6 novembre 2015. Et j'ai dû modifier la source - pas grand-chose.

Certificats: .pem dans demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps

18446744073709551615
la source
-1

Voici mon exemple de threads de serveur de socket ssl (connexion multiple) 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
la source
Veuillez inclure la solution directement dans votre message SO.
Maciej Jureczko