Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Generating cert/key during run-time for QSslSocket
Forum Update on Monday, May 27th 2025

Generating cert/key during run-time for QSslSocket

Scheduled Pinned Locked Moved General and Desktop
10 Posts 3 Posters 6.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    kshots
    wrote on last edited by
    #1

    I have a client/server app that I'm writing, and I want to secure the communications for it with randomly-generated certs/keys for every client/server (ie, no authentication, merely for privacy). The docs imply this is possible by default in their examples (none of the examples set the cert/key/CA certs, which implies that there is a default), but in my tests I get a "no shared cipher" error when attempting to do that. Also, when running "openssl s_client -connect X:Y", I get the following:

    @CONNECTED(00000003)
    140555404101328:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:

    no peer certificate available

    No client certificate CA names sent

    SSL handshake has read 0 bytes and written 308 bytes

    New, (NONE), Cipher is (NONE)
    Secure Renegotiation IS NOT supported
    Compression: NONE
    Expansion: NONE
    ---@
    ... while my server app shows the following error:

    @Client '127.0.0.1' error: Error while reading: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher@

    ... which implies that there are no certs/keys being used, hence no encryption, which causes the handshake to fail.

    Server code is fairly simple:

    @void myClass::incomingConnection(qintptr handle)
    QSslSocket * sock = new QSslSocket(this);
    if(sock->setSocketDescriptor(handle))
    {
    connect(sock, &QSslSocket::encrypted, [sock, this]
    {
    addPendingConnection(sock);
    Q_EMIT ready();
    });
    connect(sock, static_cast<void (QSslSocket:: *)(const QList<QSslError> &)>(&QSslSocket::sslErrors), [sock](const QList<QSslError> & errors)
    {
    for(const QSslError & e : errors)
    {
    qCritical("SSL Handshake error: %s", qPrintable(e.errorString()));
    }
    delete sock;
    });
    connect(sock, static_cast<void (QAbstractSocket:: *)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), [sock](QAbstractSocket::SocketError e)
    {
    switch(e)
    {
    case QAbstractSocket::RemoteHostClosedError: return;
    default:
    qWarning("Client '%s' error: %s", qPrintable(sock->peerAddress().toString()), qPrintable(sock->errorString()));
    sock->disconnectFromHost();
    }
    });
    sock->ignoreSslErrors({QSslError::SelfSignedCertificate});
    sock->startServerEncryption();
    }
    else
    {
    delete sock;
    }
    }@

    Interestingly, the QSslSocket::sslErrors() signal is never emitted, only the QAbstractSocket::error signal comes into play.

    On a side-note, the two error signals had to be static_cast'ed to work because there is ambiguity between signals and functions (QSslSocket::sslErrors and QAbstractSocket::error are overloaded functions), and gcc 4.8 doesn't know how to resolve the ambiguity without me giving some additional hints (ie, required parameters in this case).

    1 Reply Last reply
    0
    • K Offline
      K Offline
      kshots
      wrote on last edited by
      #2

      Ok, after a bit more research, I've found that Qt simply does not support randomized certificates and keys... so I've added the following to a subclass of QSslSocket to randomize a cert and key (simple enough to do since I can guarantee that OpenSSL exists if Qt supports OpenSSL on the client environment):

      @sslSocket::sslSocket(QObject *parent) : QSslSocket(parent)
      {
      int ret;
      RSA * r = nullptr;
      BIGNUM * bne = nullptr;
      BIO * bp_public = nullptr, * bp_private = nullptr;
      long size;
      char * buffer;

      const int bits = 2048;
      unsigned long e = RSA_F4;

      // 1. generate rsa key
      bne = BN_new();
      q_check_ptr(bne);
      if((ret = BN_set_word(bne, e)) != 1)
      {
      BN_free(bne);
      qFatal("BN_set_word");
      }

      r = RSA_new();
      q_check_ptr(r);
      if((ret = RSA_generate_key_ex(r, bits, bne, nullptr)) != 1)
      {
      BN_free(bne);
      RSA_free(r);
      qFatal("RSA_generate_key_ex");
      }

      // 2. save public key
      bp_public = BIO_new(BIO_s_mem());
      q_check_ptr(bp_public);
      if((ret = PEM_write_bio_RSAPublicKey(bp_public, r)) != 1)
      {
      BN_free(bne);
      RSA_free(r);
      BIO_free_all(bp_public);
      qFatal("PEM_write_bio_RSAPublicKey");
      }

      // 3. Save private key
      bp_private = BIO_new(BIO_s_mem());
      q_check_ptr(bp_private);
      if((ret = PEM_write_bio_RSAPrivateKey(bp_private, r, nullptr, nullptr, 0, nullptr, nullptr)) != 1)
      {
      BN_free(bne);
      RSA_free(r);
      BIO_free_all(bp_public);
      BIO_free_all(bp_private);
      qFatal("PEM_write_bio_RSAPrivateKey");
      }
      size = BIO_get_mem_data(bp_public, &buffer);
      q_check_ptr(buffer);
      const QByteArray cert(buffer, size);
      QSslCertificate c(cert);
      if(c.isNull())
      {
      qFatal("Failed to generate a random client certificate");
      }
      setLocalCertificate(c);
      size = BIO_get_mem_data(bp_private, &buffer);
      q_check_ptr(buffer);
      const QByteArray key(buffer, size);
      setPrivateKey(QSslKey(key, QSsl::Rsa));
      if(privateKey().isNull())
      {
      qFatal("Failed to generate a random private key");
      }
      BN_free(bne);
      RSA_free(r);
      BIO_free_all(bp_public);
      BIO_free_all(bp_private);
      }@

      This... well... doesn't appear to work, and it doesn't appear to be the fault of OpenSSL. Poking around with my debugger, the buffer is filled with the key properly, and the last byte is a '\n', which appears correct. However, the certificate ('c' in this case) is always failing the 'isNull()' check. Why? It's a valid certificate... :(

      A sample of the buffer from the certificate (randomly generated cert):

      "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAxoCMMMfEGri487WOTGN0uVfXRaE7ji2IEHudOwh45X21CnMfeVtL\njo7SdBZ2QCAIEtbYx5MBSCjItiq+brquygDvohDceyA/V0dNZFhofxjYEH+xYcO1\nskuxID6UxL4SMuwOz/6HdDROsGsj5mGxD57zFPTXcPDXOyQeg1s+K0etk3kfcvj0\n3bYC+Fs/smNTd//OHOOIrN7xs4TS4PYb63ArzLDmSbK9/gEpXQ79dcxyVEEXWx+S\nSASWq+ado4SkfGE6rBC6wzOxt8t6gGLH9bNP2WcxAofsDqOFUXmpujBr8DQrws0b\n8tfjIW2lRM3CfLCERes+i2+8dv8VjM6XTwIDAQAB\n-----END RSA PUBLIC KEY-----\n"

      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi,

        Maybe a silly question, but did you check the key QByteArray content to ensure that you have something correct in there ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        0
        • K Offline
          K Offline
          kshots
          wrote on last edited by
          #4

          Yeah, I checked that in the debugger as well - the last character the QByteArray contains is a '\n', which is apparently correct.

          On the other hand... I think I did this wrong. The docs don't say that QSslSocket works with an RSA key pair, they say it works with an X509 certificate/key pair... I'll need to figure out how to write something to generate something sensible.

          I've written SSL apps for Qt before, but in those apps it was appropriate to use full X509 certificates (ie, a CA, signed keys and certs, etc). In this application, that would be inappropriate.

          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #5

            I can't tell you, I haven't looked yet at that part of the code.

            Anyway, you should bring this question on the interest mailing list. You'll find there Qt's developers/maintainers. This forum is more oriented.

            You can also try the IRC channel, you might find the ssl module guys there

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • K Offline
              K Offline
              kshots
              wrote on last edited by
              #6

              It appears I was correct in that QSslSocket only supports X509 cert/key pairs. The following X509 generation code works properly (note: you may need to tell QSslSocket to ignore self-signed certificate errors)

              @sslSocket::sslSocket(QObject *parent) : QSslSocket(parent)
              {
              EVP_PKEY * pkey = nullptr;
              RSA * rsa = nullptr;
              X509 * x509 = nullptr;
              X509_NAME * name = nullptr;
              BIO * bp_public = nullptr, * bp_private = nullptr;
              const char * buffer = nullptr;
              long size;

              pkey = EVP_PKEY_new();
              q_check_ptr(pkey);
              rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
              q_check_ptr(rsa);
              EVP_PKEY_assign_RSA(pkey, rsa);
              x509 = X509_new();
              q_check_ptr(x509);
              ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
              X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time
              X509_gmtime_adj(X509_get_notAfter(x509), 31536000L); // not after a year from this point
              X509_set_pubkey(x509, pkey);
              name = X509_get_subject_name(x509);
              q_check_ptr(name);
              X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0);
              X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char *)"My Organization", -1, -1, 0);
              X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"My Common Name", -1, -1, 0);
              X509_set_issuer_name(x509, name);
              X509_sign(x509, pkey, EVP_sha1());
              bp_private = BIO_new(BIO_s_mem());
              q_check_ptr(bp_private);
              if(PEM_write_bio_PrivateKey(bp_private, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1)
              {
              EVP_PKEY_free(pkey);
              X509_free(x509);
              BIO_free_all(bp_private);
              qFatal("PEM_write_bio_PrivateKey");
              }
              bp_public = BIO_new(BIO_s_mem());
              q_check_ptr(bp_public);
              if(PEM_write_bio_X509(bp_public, x509) != 1)
              {
              EVP_PKEY_free(pkey);
              X509_free(x509);
              BIO_free_all(bp_public);
              BIO_free_all(bp_private);
              qFatal("PEM_write_bio_PrivateKey");
              }
              size = BIO_get_mem_data(bp_public, &buffer);
              q_check_ptr(buffer);
              setLocalCertificate(QSslCertificate(QByteArray(buffer, size)));
              if(localCertificate().isNull())
              {
              qFatal("Failed to generate a random client certificate");
              }
              size = BIO_get_mem_data(bp_private, &buffer);
              q_check_ptr(buffer);
              setPrivateKey(QSslKey(QByteArray(buffer, size), QSsl::Rsa));
              if(privateKey().isNull())
              {
              qFatal("Failed to generate a random private key");
              }

              EVP_PKEY_free(pkey); // this will also free the rsa key
              X509_free(x509);
              BIO_free_all(bp_public);
              BIO_free_all(bp_private);
              }@

              The nice thing about the above code is that it all happens in memory, no certs/keys are stored on disk. This does not guarantee that someone cannot masquerade as a "false" server, but once a connection is established, it is guaranteed to be private.

              1 Reply Last reply
              1
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #7

                Thanks for sharing ! :)

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply
                0
                • Pradeep P NP Offline
                  Pradeep P NP Offline
                  Pradeep P N
                  wrote on last edited by
                  #8

                  Hi,

                  I am trying to generate key and certificate in IOS using the same code.
                  But I am not able to create a valid QSSLKey.
                  In my logs I can see "Failed to generate a random private key" is printed.
                  Do we need some additional steps for generating key in IOS?

                  Note: same code is working fine for android build.

                  Thanks,

                  Pradeep Nimbalkar.
                  Upvote the answer(s) that helped you to solve the issue...
                  Keep code clean.

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    Hi,

                    Which Qt version are you using ? There's been some changes in the backend handling for cryptography i.e. iOS doesn't provide OpenSSL. So depending on your Qt version you may have to rebuild it with your own iOS built OpenSSL or if recent enough it should use the native backend (SecureTransport).

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply
                    0
                    • Pradeep P NP Offline
                      Pradeep P NP Offline
                      Pradeep P N
                      wrote on last edited by
                      #10

                      Hi,

                      We are using Qt5.6.2.
                      As per Qt documentation from Qt 5.6 new SSL back-end for iOS and OS X based on Secure Transport is default SSL.
                      Do we need to implement some more changes in the exsisting sample code??

                      Thanks

                      Pradeep Nimbalkar.
                      Upvote the answer(s) that helped you to solve the issue...
                      Keep code clean.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved