Я боролся с этим уже несколько дней, чтобы выяснить, как они работают.Я прочитал документацию и посмотрел на некоторые примеры, но мне все еще нужно руководство.
В частности, когда клиент вызывает connect()
и успешно подключается к хосту сервера, должен ли я выдать SSL_connect()
сразу после него, чтобы инициировать рукопожатие?Затем клиент пытается записать несколько байтов в сокет, используя SSL_write()
.
С другой стороны, сервер использует pselect()
для отслеживания любых доступных для чтения fd, готовых к чтению, и успешно выполняет вызов accept()
для входящего соединения.Должен ли я выполнить вызов SSL_accept()
сразу после возврата accept () для завершения рукопожатия?
Я заметил, что SSL_connect()
возвращает SSL_ERROR_WANT_READ
(это когда SSL_connect () выдается после вызова select () для отслеживания набора и возврата fd записи и согласно документации Openssl).
Какова здесь правильная процедура при совершении вызовов и в каком порядке?
Изменить, чтобы добавить фрагмент кода -
Client side :
err = connect(fd, addr, addrlen);
if ( err == -1 && errno == EINPROGRESS )
{
// check if this is a true error,
// or wait until connect times out
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(sfd, &fdset);
timeval tv = {F_sockwaitconnect, 0}; TEMP_FAILURE_RETRY(err = select(fd + 1,\
NULL,\
&fdset,\
NULL,\
&tv));
// what happened?
if ( err == 1 )
{
connect was successful
}
else
return 0;
const SSL_METHOD *method;
SSL_CTX *cctx;
SSL *cssl;
FILE *fp;
fp = stdout;
ERR_clear_error();
method = TLSv1_client_method();
cctx = SSL_CTX_new(method);
if ( cctx == NULL )
{
ERR_print_errors_fp(stdout);
return 0;
}
SSL_CTX_set_verify(cctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(cctx, 4);
if (SSL_CTX_load_verify_locations(cctx, "mycert.pem", NULL) == 0)
return 0;
SSL_CTX_set_options(cctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION);
ERR_clear_error();
cssl = SSL_new(cctx); /* create new SSL connection state */
SSL_set_fd(cssl, fd); * attach the socket descriptor */
ERR_clear_error();
int rconnect = SSL_ERROR_WANT_READ;
while ( rconnect == SSL_ERROR_WANT_READ || rconnect == SSL_ERROR_WANT_WRITE )
{
char *buf = (char *) malloc(124);
ERR_error_string(SSL_get_error(cssl, rconnect), buf);
ERR_clear_error();
if ( rconnect == SSL_ERROR_WANT_READ ) {
int err = 0;
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
timeval tv = {F_sockwaitconnect, 0};
TEMP_FAILURE_RETRY(err1 = select(fd + 1,\
&fdset,\
NULL,\
NULL,\
&tv));
// what happened?
if ( err == 1 )
{
rconnect = SSL_connect(cssl);
}
}
}
X509 *cert;
cert = SSL_get_peer_certificate(cssl);
char line[2000+1];
if ( cert != NULL )
{
X509_NAME_oneline(X509_get_subject_name(cert), line, MAX_SIZE);
X509_NAME_oneline(X509_get_issuer_name(cert), line1, MAX_SIZE);
X509_free(cert);
}
ERR_clear_error();
r = SSL_write(cssl, buffer, len);
< check error >
Server side :
int res = pselect(max_fd + 1, // host socket file descriptor
&fd_setw, // set of ds wait 4 incoming data
NULL, // no write operations
NULL, // no exception operations
&tm, // how much time to wait
&sig_set); // block all signals
if ( event on listening socket )
{
client = accept(sfd, &peer, &peerl);
}
else // incoming data to receive on existing connection
{
SSL *ssl;
FILE *fp = stdout;
if ( !ctx )
{
return 0;
}
ERR_clear_error();
ssl = SSL_new(ctx);
SSL_set_fd(ssl, soc);
int ret = SSL_accept(ssl);
while (ret <= 0) {
ERR_print_errors_fp(fp);
char *buf = (char *) malloc(124);
ERR_error_string(SSL_get_error(ssl, ret), buf);
ERR_clear_error();
ret = SSL_accept(ssl);
}
X509 *cert;
cert = SSL_get_peer_certificate(ssl);
char line[2000+1];
if ( cert != NULL )
{
X509_NAME_oneline(X509_get_subject_name(cert), line, MAX_SIZE);
X509_NAME_oneline(X509_get_issuer_name(cert), line1, MAX_SIZE);
X509_free(cert);
}
// get data and analyze result
int rc = 0;
bool recv_called = false;
rc = SSL_read(ssl, buffer, len);
< check error >
}
Прежде чем все вышеперечисленное, сервероткрывает, связывает и прослушивает неблокирующий сокет для любых новых входящих клиентских подключений.
Когда я запускаю вышеизложенное, клиент выполняет connect (), а сервер выполняет accept ().Сервер теперь ждет в pselect (), чтобы все fd были готовы к приему данных.С другой стороны, клиент находится в SSL_connect () и продолжает получать ошибку SSL_ERROR_WANT_READ.Функция select () возвращает сокет, готовый к чтению.Я предполагаю, что клиент ожидает части рукопожатия SSL_accept ()?Я не знаю, почему сервер ждет в pselect ().Код вокруг SSL_accept () неправильный, т.е. он зацикливается и не ищет ошибок WANT_READ и WANT_WRITE, но я не дохожу до этого пункта в коде.