连接QSslSocket与OpenSSL服务器



我试图连接我的Qt应用程序之间的SSL套接字(使用QSslSockets)和我的c++服务器运行SSL套接字(使用openssl)..

服务器代码:

int create_socket(int port)
{
   int s;
   struct sockaddr_in addr;
   addr.sin_family = AF_INET;
   addr.sin_port = htons(port);
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
   s = socket(AF_INET, SOCK_STREAM, 0);
   if (s < 0) {
      perror("Unable to create socket");
      exit(EXIT_FAILURE);
   }
   if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
      perror("Unable to bind");
      exit(EXIT_FAILURE);
   }
   if (listen(s, 1) < 0) {
      perror("Unable to listen");
      exit(EXIT_FAILURE);
   }
   return s;
}
void init_openssl()
{
   SSL_load_error_strings();
   OpenSSL_add_ssl_algorithms();
}
void cleanup_openssl()
{
   EVP_cleanup();
}
 SSL_CTX *create_context()
{
   const SSL_METHOD *method;
   SSL_CTX *ctx;
   method = SSLv23_server_method();
   ctx = SSL_CTX_new(method);
   if (!ctx) {
      perror("Unable to create SSL context");
      ERR_print_errors_fp(stderr);
      exit(EXIT_FAILURE);
   }
   return ctx;
}
void configure_context(SSL_CTX *ctx)
{    
   if(SSL_CTX_use_certificate_file(ctx, "/root/myCA/server_crt.pem", SSL_FILETYPE_PEM) > 0)
   {
      std::cout<<"Cert found"<<std::endl;
   }
   if (SSL_CTX_use_PrivateKey_file(ctx, "/root/myCA/server_key.pem", SSL_FILETYPE_PEM) > 0 ) {
      std::cout<<"Key found"<<std::endl;
   }
   if(SSL_CTX_check_private_key(ctx) > 0)
   {
      std::cout<<"Key valid"<<std::endl;
   }
}
int main(int argc, char **argv)
{
   int sock;
   SSL_CTX *ctx;
   init_openssl();
   ctx = create_context();
   configure_context(ctx);
   sock = create_socket(3000);
   while(1) {
       struct sockaddr_in addr;
       uint len = sizeof(addr);
       SSL *ssl;
       const char reply[] = "testn";
      int client = accept(sock, (struct sockaddr*)&addr, &len);
      if (client > 0) {
          std::cout<<"Client accepted..."<<std::endl;
      }
      else
      {
          perror("Unable to accept");
          exit(EXIT_FAILURE);
      }
      ssl = SSL_new(ctx);
      SSL_set_fd(ssl, client);
      if (SSL_accept(ssl) <= 0) {
          ERR_print_errors_fp(stderr);
      }
      else {
          SSL_write(ssl, reply, strlen(reply));
      }
      SSL_free(ssl);
      close(client);
    }
  close(sock);
  SSL_CTX_free(ctx);
  cleanup_openssl();

}

Qt客户端代码:
 SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent)
 {
   connect(&client,SIGNAL(encrypted()),this,SLOT(ConnectionEstablished()));
   connect(&client,SIGNAL(sslErrors(const QList<QSslError>&)),this,SLOT(ErrorOccured(const QList<QSslError> &)));
   QList<QSslCertificate>
   trusted_ca=QSslCertificate::fromPath("/Users/test/Desktop/server_crt.pem");
   if(trusted_ca.empty())
   {
      qDebug()<<"Error not trusted Ca.";
   }
   client.setCaCertificates(trusted_ca);
   client.connectToHostEncrypted(*my ip address*,3000);
 }
 void SSLSOCKET::ErrorOccured(const QList<QSslError> &error)
 {
    qDebug()<<"ERROR HERE----:";
    qDebug()<<error;
 }
 void SSLSOCKET::ConnectionEstablished()
 {
    qDebug()<<"CONNECTION WORKED------:";
    if(!client.waitForEncrypted())
    {
       qDebug()<<client.errorString();
    }
    else
    {
       qDebug()<<"Encrypted Connection Established...";
    }
  }

我可以看到客户端和服务器之间的连接,但是client. waitforencrypted()显示'Unknown Error'..

任何想法?

您在connected()处理程序中调用waitForEncrypted()。客户机还没有实际发起SSL握手,因此您还不能等待它。根据connectToHostEncrypted()文档:

port上启动到设备hostname的加密连接,使用mode作为OpenMode。这相当于调用connectToHost()来建立连接,然后调用startClientEncryption()protocol参数可以用来指定使用哪个网络协议(例如:IPv4或IPv6)。

QSslSocket首先进入HostLookupState。然后,在进入事件循环或waitFor...()函数之一之后,它进入ConnectingState发出connected(),然后启动SSL客户端握手。每次状态变化时,QSslSocket发出信号stateChanged()

如果你想这样处理connected(),你将不得不使用connectToHost()而不是connectToHostEncrypted(),然后单独调用startClientEncryption():

SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent)
{
    connect(&client, SIGNAL(connected()), this, SLOT(ConnectionEstablished()));
    ...
    client.connectToHost(*my ip address*, 3000);
}
void SSLSOCKET::ConnectionEstablished()
{
    client.startClientEncryption();
    if (!client.waitForEncrypted())
        ...
}

EDIT:删掉。我以为你在处理connected()信号,但我现在看到你在处理encrypted()信号。在这种情况下:

如果SSL握手成功,QSslSocket发出encrypted()

所以你根本不需要使用waitForEncrypted():
void SSLSOCKET::ConnectionEstablished()
{
    qDebug()<<"CONNECTION WORKED------:";
    qDebug()<<"Encrypted Connection Established...";
}

即使你调用了它,它也应该返回true:

等待,直到套接字完成SSL握手并发出encrypted()msecs毫秒,以先到者为准。如果encrypted()已经发出,这个函数返回true;否则(例如,套接字断开连接,或SSL握手失败),返回false。

因此,除非在握手完成后套接字被断开连接,或者在加密状态实际更改之前发出encrypted(),或者发生其他一些不可预见的错误,否则我看不到waitForEncrypted()encrypted()处理程序中返回false的任何理由。

最新更新