web-dev-qa-db-fra.com

Transformez un simple socket en un socket SSL

J'ai écrit de simples programmes en C, 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 le lie ensuite à 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 et l'écrit ensuite.

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

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

104
David Mape

Il y a plusieurs étapes à suivre pour utiliser OpenSSL. Vous devez disposer d'un certificat SSL pouvant 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 y a beaucoup de bons tutoriels là-bas.

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 de la fonctionnalité. Vous voudrez peut-être 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);

Mise à jour Le SSL_CTX_new Doit être appelé avec la méthode TLS la mieux adaptée à vos besoins afin de prendre en charge les versions les plus récentes de la sécurité. SSLv23_server_method(). Voir: OpenSSL SSL_CTX_new description

TLS_method (), TLS_server_method (), TLS_client_method (). Voici les méthodes générales version-flexible Méthodes SSL/TLS. La version réelle du protocole utilisée sera négociée avec 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.

135
CaptainBli

OpenSSL est assez difficile. Il est facile de jeter accidentellement toute votre sécurité en ne négociant pas correctement. (Heck, j'ai été personnellement piqué par un bug qui empêchait curl de lire correctement les alertes OpenSSL et de ne pas pouvoir parler à certains sites.)

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

16
BraveNewCurrency

Pour d'autres comme moi:

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

Vous devrez probablement trouver une version qui fonctionne. J'ai initialement posté cette réponse le 6 novembre 2015. Et j'ai dû modifier le source - pas grand chose.

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

7

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;
}
0
Fanex