sockets tcp openssl

sockets - SSL_accept() falla con el valor de retorno-1



tcp openssl (1)

Para comprender SSL/TLS , descargué OpenSSL-1.0.2k en Windows-7 y compilé con el compilador Cygwin gcc 64 bit . Tomé off-the-shelf ejemplo de servidor / cliente del ejemplo del servidor / cliente OpenSSL en c y compilé con cygwin gcc . La compilación es exitosa en el primer intento. Ejecuté el servidor y el cliente desde cmd con los siguientes comandos.

(Server) D:/>ssl-server.exe 5000 (Client) D:/>ssl-client.exe 127.0.0.1 5000

El cliente sale sin ninguna respuesta pero, por otro lado, el servidor muestra que ha hecho una conexión, por ejemplo;

Connection: 127.0.0.1:50475

y espera en la línea siguiente infinitamente.

Luego comencé a depurar el lado del servidor y encontré que, SSL_accept() en el SSL_accept() void Servlet(SSL* ssl) devuelve un valor de -1 , que no se espera. Consulté documentación de OpenSSL openSSL DOC ;

El protocolo de enlace TLS / SSL no tuvo éxito porque se produjo un error fatal en el nivel del protocolo o se produjo un error de conexión. El cierre no estaba limpio. También puede ocurrir que se necesite acción para continuar la operación de BIO sin bloqueo. Llame a SSL_get_error () con el valor de retorno ret para averiguar el motivo.

SSL_get_error() devuelve SSL_ERROR_SYSCALL . Revisé el valor de errno justo después de esta llamada y no veo no error . El código completo del método Servlet sigue. El resto del código es el mismo que en el enlace.

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"; int ret; ret = SSL_accept(ssl); /* do SSL-protocol accept */ if ( ret == -1 ) { // printf(" SSL_accept() returned -1/n"); switch(SSL_get_error(ssl, ret) ) { case SSL_ERROR_SYSCALL: perror("errno"); break; default: printf( "default" ); break; } exit(-1); } else if ( ret == 0) { printf(" SSL_accept() returned 0/n"); exit(-1); } else if ( ret == 1) // The TLS/SSL connection has been established. { 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 */ }


  1. Cuando no golpea uno de los casos SSL_ERROR_ que ha enumerado, debe rastrear el valor de SSL_get_error() para que pueda comenzar la depuración. En lugar de solo tirar las manos.
  2. En este caso, el valor fue SSL_ERROR_SYSCALL . No lo captó donde creía que debería porque case (SSL_ERROR_SYSCALL || SSL_ERROR_SSL || SSL_ERROR_WANT_CONNECT || SSL_ERROR_WANT_ACCEPT): no hace lo que usted piensa. Se convertirá en el case 1 debido a la semántica de || . Debe haber declaraciones de case por separado para cada valor.
  3. SSL_ERROR_SYSCALL significa que el error subyacente está en errno , según la documentación que citó usted mismo, lo que significa que debe rastrear eso . En lugar de solo tirar las manos. Y tenga en cuenta que debe hacerlo antes de llamar a cualquier otra llamada del sistema (como write() través de printf() ), por lo que podría ayudar a guardar errno inmediatamente.
  4. Puede imprimir errno directamente con printf("errno=%d/n", errno) , pero sería más útil imprimir el mensaje de error, que puede hacer con perror() o printf("error=%s/n", syserror(errno)) .
  5. El valor de SSL_get_error() no es un valor errno , y tampoco es el -1 original con el que comenzó. Un valor errno proviene de la variable errno .
  6. Sin embargo, no debe hacer ninguna de estas cosas a menos que SSL_accept() devuelva -1, para lo cual no hay evidencia real aquí.

Entonces, es muy posible que no haya ningún error aquí.