solucion - Comunicación entre el cliente y el servidor mediante ssl c/c++: el protocolo SSL no funciona
protocolo ssl puerto (3)
Estoy intentando usar un ejemplo de cliente / servidor SSL de: http://simplestcodings.blogspot.com.br/2010/08/secure-server-client-using-openssl-in-c.html para crear una conexión segura usando SSLv3. Hice algunos cambios para solicitar el certificado en el lado del servidor, la comunicación funciona bien y se entiende en ambos lados. Por lo tanto, mi problema es que cuando el cliente se conecta al servidor, la comunicación de protocolo SSLv3 no funciona, verifiqué utilizando wirkeshark y en el campo de protocolo solo se muestra TCP, o IPA (RSL Malformed Packet). ¿Alguien puede ayudarme? ¡Gracias!
He creado mis certificados siguiendo el tutorial https://help.ubuntu.com/community/OpenSSL .
Aquí está mi código de cliente:
//SSL-Client.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL -1
//Added the LoadCertificates how in the server-side makes.
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate/n");
abort();
}
}
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = SSLv3_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server''s certificate */
if ( cert != NULL )
{
printf("Server certificates:/n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s/n", line);
free(line); /* free the malloc''ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s/n", line);
free(line); /* free the malloc''ed string */
X509_free(cert); /* free the malloc''ed certificate copy */
}
else
printf("No certificates./n");
}
int main()
{ SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
char hostname[]="127.0.0.1";
char portnum[]="5000";
char CertFile[] = "/home/myCA/cacert.pem";
char KeyFile[] = "/home/myCA/private/cakey.pem";
SSL_library_init();
ctx = InitCTX();
LoadCertificates(ctx, CertFile, KeyFile);
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{ char *msg = "Hello???";
printf("Connected with %s encryption/n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
printf("Received: /"%s/"/n", buf);
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
Y el servidor:
//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can''t bind port");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("Can''t configure listening port");
abort();
}
return sd;
}
SSL_CTX* InitServerCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = SSLv3_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
//New lines
if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
ERR_print_errors_fp(stderr);
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
ERR_print_errors_fp(stderr);
//End new lines
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx))
{
fprintf(stderr, "Private key does not match the public certificate/n");
abort();
}
//New lines - Force the client-side have a certificate
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_verify_depth(ctx, 4);
//End new lines
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if ( cert != NULL )
{
printf("Server certificates:/n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s/n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s/n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates./n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>/n/n";
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: /"%s/"/n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main()
{ SSL_CTX *ctx;
int server;
char portnum[]="5000";
char CertFile[] = "/home/myCA/mycert.pem";
char KeyFile[] = "/home/myCA/mycert.pem";
SSL_library_init();
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, CertFile, KeyFile); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d/n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
Como dije en los comentarios a una de sus preguntas anteriores , el hecho de que obtenga un " Paquete con formato incorrecto: GSM sobre IP " o algo extraño aquí es normal.
Está utilizando el puerto 5000, que normalmente está reservado para el protocolo commplex-main
. Por lo tanto, sin ningún tipo de información adicional, Wireshark intenta analizar el tráfico que ve con los decodificadores commplex-main
.
Por supuesto, dado que los datos que está intercambiando en ese puerto son de hecho SSL / TLS (porque está usando un puerto que normalmente no se usa para eso), descodifíquelos como si commplex-main
a una cantidad de datos impares. Mensajes sobre paquetes mal formados.
Wireshark solo adivina el protocolo usando el número de puerto que ve. Debe indicarle que pruebe un decodificador diferente, si no está utilizando el puerto estándar para ese protocolo.
Más específicamente, haga clic derecho en un paquete y elija Decodificar como ... -> Transporte -> SSL .
Con los programas de servidor y cliente anteriores, estaba recibiendo el siguiente error:
140671281543104: error: 140890B2: Rutinas SSL: SSL3_GET_CLIENT_CERTIFICATE: no se devolvió el certificado: s3_srvr.c: 3292:
Yo había generado certificados autofirmados usando el procedimiento mencionado en https://help.ubuntu.com/community/OpenSSL .
Después de hacer malabares con el error durante un día, descubrí que el error se debía a que la CA autogenerada no estaba en la cadena de confianza de la máquina que estaba usando.
Para agregar la CA a la cadena de confianza en RHEL-7, se puede seguir el siguiente procedimiento:
To add a certificate in the simple PEM or DER file formats to the
list of CAs trusted on the system:
Copy it to the
/etc/pki/ca-trust/source/anchors/
subdirectory, and run the
update-ca-trust
command.
If your certificate is in the extended BEGIN TRUSTED file format,
then place it into the main source/ directory instead.
Creo que el procedimiento anterior puede seguirse también para fedora. Si esto no funciona, puede ser útil explorar los comandos como "update-ca-certificados". Espero que esto le sea útil a alguien.
debe modificar su código (servidor): su código:
int main()
{ SSL_CTX *ctx;
int server;
**char portnum[]="5000";**
char CertFile[] = "/home/myCA/mycert.pem";
char KeyFile[] = "/home/myCA/mycert.pem";
SSL_library_init();
**portnum = strings[1];**
en su lugar deberías usar esto:
int main(int argc, char **argv)
{ SSL_CTX *ctx;
int server;
//char portnum[]="5000"; ---> You can pass it as an argument
char CertFile[] = "/home/myCA/mycert.pem";
char KeyFile[] = "/home/myCA/mycert.pem";
SSL_library_init();
//portnum = strings[1];
portnum = argv[1]; // ---> You can pass port number here, instead of put it in the code
Tengo esta salida (cliente):
toc@UnixServer:~$ ./ssl_client
Connected with AES256-SHA encryption
Server certificates:
Subject: /C=FR/ST=Some-State/L=PARIS/O=TOC/OU=TOC/CN=TOC/[email protected]
Issuer: /C=FR/ST=Some-State/L=PARIS/O=TOC/OU=TOC/CN=TOC/[email protected]
Received: "<html><body><pre>Hello???</pre></body></html>
"
Y esta salida (servidor):
Connection: 127.0.0.1:59066
Server certificates:
Subject: /C=FR/ST=Some-State/L=PARIS/O=TOC/OU=TOC/CN=TOC/[email protected]
Issuer: /C=FR/ST=Some-State/L=PARIS/O=TOC/OU=TOC/CN=TOC/[email protected]
Client msg: "Hello???"
Cuando usa una herramienta como ssldump (http://www.rtfm.com/ssldump/) (en el cuadro de Unix), puede ver claramente lo que está pasando:
toc@UnixServer:~$sudo ssldump -i lo port 5000
New TCP connection #1: localhost(59071) <-> localhost(5000)
1 1 0.0012 (0.0012) C>S Handshake
ClientHello
Version 3.0
cipher suites
Unknown value 0xc014
Unknown value 0xc00a
SSL_DHE_RSA_WITH_AES_256_CBC_SHA
SSL_DHE_DSS_WITH_AES_256_CBC_SHA
Unknown value 0x88
Unknown value 0x87
Unknown value 0xc00f
Unknown value 0xc005
SSL_RSA_WITH_AES_256_CBC_SHA
Unknown value 0x84
Unknown value 0xc012
Unknown value 0xc008
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
Unknown value 0xc00d
Unknown value 0xc003
SSL_RSA_WITH_3DES_EDE_CBC_SHA
Unknown value 0xc013
Unknown value 0xc009
SSL_DHE_RSA_WITH_AES_128_CBC_SHA
SSL_DHE_DSS_WITH_AES_128_CBC_SHA
Unknown value 0x9a
Unknown value 0x99
Unknown value 0x45
Unknown value 0x44
Unknown value 0xc00e
Unknown value 0xc004
SSL_RSA_WITH_AES_128_CBC_SHA
Unknown value 0x96
Unknown value 0x41
Unknown value 0xc011
Unknown value 0xc007
Unknown value 0xc00c
Unknown value 0xc002
SSL_RSA_WITH_RC4_128_SHA
SSL_RSA_WITH_RC4_128_MD5
SSL_DHE_RSA_WITH_DES_CBC_SHA
SSL_DHE_DSS_WITH_DES_CBC_SHA
SSL_RSA_WITH_DES_CBC_SHA
SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
SSL_RSA_EXPORT_WITH_RC4_40_MD5
Unknown value 0xff
compression methods
unknown value
NULL
1 2 0.0019 (0.0006) S>C Handshake
ServerHello
Version 3.0
session_id[32]=
13 e2 5a f0 10 93 18 56 c8 66 54 94 29 ab 8b 2d
7b c6 9c 3b 7b ea c7 54 e6 86 7d 3a 56 8c 96 14
cipherSuite SSL_RSA_WITH_AES_256_CBC_SHA
compressionMethod unknown value
1 3 0.0019 (0.0000) S>C Handshake
Certificate
1 4 0.0019 (0.0000) S>C Handshake
CertificateRequest
certificate_types rsa_sign
certificate_types dss_sign
ServerHelloDone
1 5 0.0155 (0.0136) C>S Handshake
Certificate
1 6 0.0155 (0.0000) C>S Handshake
ClientKeyExchange
1 7 0.0155 (0.0000) C>S Handshake
CertificateVerify
Signature[128]=
ac 94 31 89 64 75 20 5f 4f 00 73 4e e8 de 51 b7
f1 bb 16 da 63 b1 8d e9 15 9b af f8 32 d7 84 f5
b5 7d 4f 48 1c 2b 41 58 81 d3 a8 50 40 25 90 95
44 de 9d bb c4 79 5c 64 a8 a9 28 f4 16 7c 0e 17
b2 77 cf b0 8c a9 90 50 34 a5 76 a2 57 39 8d 37
12 d8 a5 8d f4 08 3a 1e 83 7e 6c 0a e9 75 ec 85
3d 56 f2 2e 4a 7d 71 88 29 26 99 40 43 4e f3 29
26 bf eb 15 be 36 22 72 f3 d9 be 4a e3 c9 0b cc
1 8 0.0155 (0.0000) C>S ChangeCipherSpec
1 9 0.0155 (0.0000) C>S Handshake
1 10 0.0245 (0.0089) S>C ChangeCipherSpec
1 11 0.0245 (0.0000) S>C Handshake
1 12 0.0250 (0.0005) C>S application_data
1 13 0.0250 (0.0000) C>S application_data
1 14 0.0258 (0.0007) S>C application_data
1 15 0.0258 (0.0000) S>C application_data
1 0.0261 (0.0002) C>S TCP FIN
1 0.0275 (0.0013) S>C TCP FIN
Saludos.