SSL_Read () возвращает SSL_ERROR_ZERO_RETURN, но ERR_get_error () равно 0 - PullRequest
0 голосов
/ 08 мая 2018

Я пишу неблокирующий клиент Websocket и использую OpenSSL для уровня TLS. Я могу подключиться к удаленному серверу, выполнить квитирование TLS, отправить запрос на обновление, получить подтвержденный ответ об обновлении и получить реальный ответ через веб-сокет, прежде чем уровень TLS отключится с SSL_ERROR_ZERO_RETURN.

SSL_get_error(...) возвращает: 6 // SSL_ERROR_ZERO_RETURN

ERR_error_string(ERR_get_error(), nullptr) возвращает: error:00000000:lib(0):func(0):reason(0)

Насколько я понимаю, ERR_get_error() должен появиться и вернуть первую ошибку в очередь ошибок, а SSL_get_error() вернет последнюю ошибку функции SSL_*. Я не понимаю, почему SSL_get_error() возвращает значение ошибки, а ERR_get_error() - нет. Согласно этому предыдущему вопросу переполнения стека , SSL_get_error() НЕ вызывает ERR_get_error().

Следующий код вызывается повторно (поскольку это неблокирующий сокет):

ERR_clear_error();
int ret = SSL_read(...);
if (ret > 0) {
  // read bytes from socket
} else {
  int err_code = SSL_get_error(ssl_session_, ret);
  if (err_code == SSL_ERROR_ZERO_RETURN || err_code == SSL_ERROR_SYSCALL || err_code == SSL_ERROR_SSL) {
    sprintf("Disconnected: %d %s", err_code, ERR_error_string(ERR_get_error(), nullptr));
    // Disconnect Code
  }
}

У меня есть два вопроса:

  1. Почему я не получаю значение ошибки для ERR_get_error ()?

  2. Почему я так быстро отключаюсь после установления сеанса TLS и Websocket?

РЕДАКТИРОВАТЬ 1

Я использовал wireshark для захвата пакетов между клиентом и сервером. Я подтвердил, что квитирование TLS, обновление веб-сокета и первоначальный ответ сервера прошли успешно. Я заметил, что после первоначального ответа сервера мой клиент получает Encrypted Alert 21 с сервера, который, по моему мнению, является фатальной ошибкой, и объясняет, почему сеанс TLS немедленно завершается, а моя очередь ошибок SSL пуста (хотя это, вероятно, проблема на стороне клиента, Я не думаю, что это результат недавнего действия), и как бы объясняет значение SSL_ERROR_ZERO_RETURN, которое я получаю после SSL_Read.

Я не уверен, что влечет за собой Encrypted Alert 21. Это может быть сертификат, который я использую (самоподписанный). Нужно расследовать дальше.

1 Ответ

0 голосов
/ 09 мая 2018

Хорошо, коренная причина проблемы была определена, но было прыгнуто много обручей, и время было потрачено, чтобы добраться туда. Мне удалось расшифровать трафик SSL, захватив мастер-ключ с помощью метода OpenSSL, SSL_SESSION_get_master_key () и случайного значения Client Hello с помощью wireshark.

Соответствующий код для вывода мастер-ключа после SSL_Connect:

ERR_clear_error();
int ret = SSL_connect(ssl_ptr);
if (ret > 0) {
    SSL_SESSION * ssl_session = SSL_get_session(ssl_ptr);
    if(ssl_session != NULL) {
      unsigned char master_key_buf[256];
      size_t outlen = sizeof(master_key_buf);
      size_t buf_size = SSL_SESSION_get_master_key(ssl_session, master_key_buf, outlen);
      if(outlen > 0) {
        char hex_encoded_master_buf[513];
        // hex encode the master key
        for(size_t i = 0; i < buf_size; ++i) {
          sprintf(&hex_encoded_master_buf[2*i], "%02x", master_key_buf[i]);
        }
        hex_encoded_master_buf[(2*buf_size)] = '\0';
        // log out the hex-encoded master key in master buf here
      } 
    }
}

Используя формат NSS Key Log CLIENT_RANDOM в wireshark для расшифровки захваченного трафика SSL, я смог изучить вышеупомянутый Encrypted Alert 21, который в итоге оказался просто FINS WebSocket, и close_notify.

Оказывается, основная причина заключалась в том, что во время рукопожатия мое сообщение с запросом на обновление WSS действительно содержало правильные заголовки, но я фактически отправлял полезную нагрузку с ним. Это был случай установки размера с использованием sizeof буфера сообщений вместо strlen при отправке сообщения. Сервер отлично бы проанализировал сообщение Upgrade и успешно завершил рукопожатие, но в следующий раз, когда он проверял свой сокет, он считывал мусор, когда ожидал сообщение WSS. Это вызвало внезапное закрытие соединения веб-сокета.

В заключение, чтобы ответить на два моих первоначальных вопроса:

  1. Почему я не получаю значение ошибки для ERR_get_error ()?

Соединение разрывается на стороне сервера, а очередь ошибок будет содержать ошибки на стороне клиента, которых нет, по крайней мере на уровне SSL / TLS.

  1. Почему я так быстро отключаюсь после установления сеанса TLS и Websocket?

Мой начальный запрос на обновление содержал действительный запрос на обновление Websocket, за которым следовали данные мусора. Сервер проанализировал запрос на обновление Websocket, подтвердил обновление и начал отправлять данные обратно. В следующий раз, когда сервер проверил свой сокет, у него все еще были значения мусора, которые были отправлены с оригинальным Запросом на обновление Websocket. Поскольку сервер не распознал его как допустимое сообщение Websocket или что-либо еще в этом отношении, он решил разорвать соединение с close_notify.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...