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 */
}
- 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. - En este caso, el valor fue
SSL_ERROR_SYSCALL
. No lo captó donde creía que debería porquecase (SSL_ERROR_SYSCALL || SSL_ERROR_SSL || SSL_ERROR_WANT_CONNECT || SSL_ERROR_WANT_ACCEPT):
no hace lo que usted piensa. Se convertirá en elcase 1
debido a la semántica de||
. Debe haber declaraciones decase
por separado para cada valor. - 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 (comowrite()
través deprintf()
), por lo que podría ayudar a guardarerrno
inmediatamente. - Puede imprimir
errno
directamente conprintf("errno=%d/n", errno)
, pero sería más útil imprimir el mensaje de error, que puede hacer conperror()
oprintf("error=%s/n", syserror(errno))
. - El valor de
SSL_get_error()
no es un valorerrno
, y tampoco es el -1 original con el que comenzó. Un valorerrno
proviene de la variableerrno
. - 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í.