Вызовы SSL_connect () и SSL_accept () - PullRequest
0 голосов
/ 24 ноября 2018

Я боролся с этим уже несколько дней, чтобы выяснить, как они работают.Я прочитал документацию и посмотрел на некоторые примеры, но мне все еще нужно руководство.

В частности, когда клиент вызывает 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, но я не дохожу до этого пункта в коде.

1 Ответ

0 голосов
/ 24 ноября 2018

SSL_connect можно вызывать всякий раз, когда connect заканчивается.Поскольку и connect, и SSL_connect необходимо обмениваться данными с одноранговым узлом, они могут не сразу преуспеть при использовании неблокирующих сокетов.Если SSL_connect возвращается с ошибкой SSL_WANT_READ или SSL_WANT_WRITE, вы должны вызывать его снова после того, как новые данные станут доступны для сокета (SSL_WANT_READ) или сокет доступен для записи (SSL_WANT_WRITE).Вы можете проверить или дождаться этого с помощью select, pselect, poll, epoll, kqueue или любого другого API, предоставляемого вашей ОС для этого.

SSL_accept и accept аналогичны, т. Е. SSL_accept может быть вызван сразу после успешного accept, может не удастся немедленно, так как требуется обмен данными с клиентом SSL, и поэтому вам придется вызывать его снова, если он возвращает ошибку SSL_WANT_READ или SSL_WANT_WRITE.

Обратите внимание, что SSL_write и SSL_read также могут привести к таким ошибкам.то есть вам нужно работать с SSL_WANT_READ и SSL_WANT_WRITE также для этих функций, а также так же, как с SSL_connect и SSL_accept.Может даже случиться, что SSL_read приведет к SSL_WANT_WRITE, поскольку повторное согласование SSL может произойти, даже если сеанс SSL уже был установлен.

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