Convierta un socket simple en un socket SSL

115

Escribí programas simples en C, que utilizan sockets ('cliente' y 'servidor'). (Uso de UNIX / Linux)

El lado del servidor simplemente crea un socket:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

Y luego lo une a sockaddr:

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

Y escucha (y acepta y lee):

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

El cliente crea el socket y luego escribe en él.

Ahora, quiero convertir esta simple conexión en una conexión SSL, de la manera más sencilla, idílica, ordenada y rápida.

Intenté agregar OpenSSL a mi proyecto, pero no encuentro una manera fácil de implementar lo que quiero.

David Mape
fuente
Si está buscando "una conexión segura" en lugar de SSL en particular, puede buscar algo como proxychains.sourceforge.net que reside fuera de su aplicación y configurarlo para enviar tráfico a través de una conexión SSH. En cuanto a SSL en la aplicación, OpenSSL es bastante fácil si comprende cómo se supone que funciona SSL / TLS. Si desea una alternativa, pruebe yaSSL o gnuTLS.
Borealid
3
Defina "vía fácil". OpenSSl es el estándar para programadores de C. Si tiene dificultades con él, debe preguntar al respecto.
Marqués de Lorne
Marque este: Introducción a la programación OpenSSL (Parte I) . La segunda parte es demasiado avanzada y difícil para mí. Pero vale la pena echarle un vistazo a la parte 2.
Rick
Consulte también la programación segura con la API de OpenSSL . Pero acabo de escuchar opiniones sobre lo malo que es Openssl y otras alternativas que vale la pena probar.
Rick
Otra opción es usar una herramienta de envoltura SSL externa como stunnel, por ejemplo , el stunnel4paquete está en distribuciones basadas en Debian y es fácil de usar. Existen algunas limitaciones en comparación con agregar el soporte SSL adecuado en su servidor, pero puede ser bueno para una solución rápida. Me gusta stunnel porque parece encajar con el enfoque de las herramientas de software de UNIX.
Sam Watkins

Respuestas:

150

Hay varios pasos al utilizar OpenSSL. Debe tener un certificado SSL hecho que pueda contener el certificado con la clave privada asegúrese de especificar la ubicación exacta del certificado (este ejemplo lo tiene en la raíz). Hay muchos buenos tutoriales por ahí.

Algunos incluyen:

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

Necesitará inicializar 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);
}

Ahora, la mayor parte de la funcionalidad. Es posible que desee agregar un bucle while en las conexiones.

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

Luego podrá leer o escribir usando:

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

La actualización seSSL_CTX_new debe llamar con el método TLS que mejor se adapte a sus necesidades para admitir las versiones más recientes de seguridad, en lugar de SSLv23_server_method(). Ver: OpenSSL SSL_CTX_new descripción

TLS_method (), TLS_server_method (), TLS_client_method (). Estos son los métodos SSL / TLS de versión flexible de uso general . La versión real del protocolo utilizada se negociará con la versión más alta que el cliente y el servidor admitan mutuamente. Los protocolos admitidos son SSLv3, TLSv1, TLSv1.1, TLSv1.2 y TLSv1.3.

CaptainBli
fuente
9
no tan "simple" como pensaba, pero finalmente (¡gracias a Dios!) veo un código. ¿Es esto multiplataforma o solo para sistemas tipo Unix / Unix?
juliomalegria
3
He usado código similar en múltiples plataformas: arm, linux y windows.
CaptainBli
2
Sin ifembargo, el último está mal. Debería ser if (ssl_err <= 0) {solo entonces es un error. SSL_accept()devuelve 1el éxito, 0el "fallo controlado" y -1el "fallo fatal". Consulte la página de manual.
Jite
2
Además, los cifrados DH no funcionarán si SSL_CTX_set_tmp_dh[_callback]()no se llaman. Acabo de descubrir por las malas que los cifrados NULL no funcionarán sin él, lo que genera la alerta número 40.
Roman Dmitrienko
5
@DevNull SSLv23_server_method()indica que el servidor comprende SSLv2 y v3 y ahora está obsoleto. Para admitir TLS 1.1 y 1.2, reemplace ese método con TLS_server_method(). fuente
ezPaint
17

OpenSSL es bastante difícil. Es fácil deshacerse accidentalmente de toda su seguridad al no negociar exactamente correctamente. (Diablos, personalmente me ha picado un error en el que curl no estaba leyendo las alertas de OpenSSL exactamente correctamente y no podía hablar con algunos sitios).

Si realmente quiere algo rápido y sencillo, coloque Stud delante de su programa y llámelo un día. Tener SSL en un proceso diferente no lo ralentizará: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html

ValienteNuevoMoneda
fuente
11
Esta es una respuesta práctica, pero en realidad no responde a la pregunta.
Suiza
4
STUD se abandonó en 2016. El archivo
Charles
7

Para otros como yo:

Una vez hubo un ejemplo en la fuente SSL en el directorio demos/ssl/con código de ejemplo en C ++. Ahora está disponible solo a través del historial: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Probablemente tendrás que encontrar una versión que funcione. Originalmente publiqué esta respuesta el 6 de noviembre de 2015. Y tuve que editar la fuente, no mucho.

Certificados: .pem en demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps

18446744073709551615
fuente
-1

Aquí mi ejemplo de subprocesos de servidor de socket ssl (conexión múltiple) 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
fuente
Incluya la solución directamente en su publicación SO.
Maciej Jureczko