From f80450176ae0f509521fe33dc7ab1fa807da5001 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 5 May 2018 21:59:30 -0700 Subject: [PATCH] Fix SSL on macOS --- app/identitymanager.cpp | 48 ++++++++++++++++++++++++++++++----------- app/identitymanager.h | 4 ++++ app/main.cpp | 4 ++++ app/nvhttp.cpp | 5 +---- 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/app/identitymanager.cpp b/app/identitymanager.cpp index 1d61a9cc..5d217191 100644 --- a/app/identitymanager.cpp +++ b/app/identitymanager.cpp @@ -10,7 +10,6 @@ #include #include -#include IdentityManager::IdentityManager() { @@ -49,14 +48,8 @@ IdentityManager::IdentityManager() m_CachedPemCert = certificateFile.readAll(); m_CachedPrivateKey = privateKeyFile.readAll(); - // Make sure it really loads - if (!QSslKey(m_CachedPrivateKey, QSsl::Rsa).isNull() && !QSslCertificate(m_CachedPemCert).isNull()) - { - qDebug() << "Loaded cached identity key pair from disk"; - return; - } - - qDebug() << "Regenerating corrupted local key pair"; + qDebug() << "Loaded cached identity key pair from disk"; + return; } privateKeyFile.close(); @@ -117,13 +110,42 @@ IdentityManager::IdentityManager() BIO_free(biokey); BIO_free(biocert); - // Ensure we can actually consume the keys we just wrote - Q_ASSERT(!QSslCertificate(m_CachedPemCert).isNull()); - Q_ASSERT(!QSslKey(m_CachedPrivateKey, QSsl::Rsa).isNull()); - qDebug() << "Wrote new identity credentials to disk"; } +QSslConfiguration +IdentityManager::getSslConfig() +{ + BIO* bio = BIO_new_mem_buf(m_CachedPrivateKey.data(), -1); + THROW_BAD_ALLOC_IF_NULL(bio); + + EVP_PKEY* pk = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr); + BIO_free(bio); + + bio = BIO_new(BIO_s_mem()); + THROW_BAD_ALLOC_IF_NULL(bio); + + // We must write out our PEM in the old PKCS1 format for SecureTransport + // on macOS/iOS to be able to read it. + BUF_MEM* mem; + BIO_get_mem_ptr(bio, &mem); + PEM_write_bio_PrivateKey_traditional(bio, pk, nullptr, nullptr, 0, nullptr, 0); + + QSslCertificate cert = QSslCertificate(m_CachedPemCert); + QSslKey key = QSslKey(QByteArray::fromRawData(mem->data, mem->length), QSsl::Rsa); + Q_ASSERT(!cert.isNull()); + Q_ASSERT(!key.isNull()); + + BIO_free(bio); + EVP_PKEY_free(pk); + + QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); + sslConfig.setLocalCertificate(cert); + sslConfig.setPrivateKey(key); + + return sslConfig; +} + QString IdentityManager::getUniqueId() { diff --git a/app/identitymanager.h b/app/identitymanager.h index 954925a2..267c1825 100644 --- a/app/identitymanager.h +++ b/app/identitymanager.h @@ -1,6 +1,7 @@ #pragma once #include +#include class IdentityManager { @@ -16,6 +17,9 @@ public: QByteArray getPrivateKey(); + QSslConfiguration + getSslConfig(); + private: QDir m_RootDirectory; diff --git a/app/main.cpp b/app/main.cpp index ef04b215..503c270f 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -7,6 +7,10 @@ int main(int argc, char *argv[]) // i.e. it's in the window, and not the top left of the screen QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar); + // This avoids using the default keychain for SSL, which may cause + // password prompts on macOS. + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + QApplication a(argc, argv); MainWindow w; w.show(); diff --git a/app/nvhttp.cpp b/app/nvhttp.cpp index 520eed11..4a6ccdcd 100644 --- a/app/nvhttp.cpp +++ b/app/nvhttp.cpp @@ -221,10 +221,7 @@ NvHTTP::openConnection(QUrl baseUrl, QNetworkRequest request = QNetworkRequest(url); // Add our client certificate - QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); - sslConfig.setLocalCertificate(QSslCertificate(m_Im.getCertificate())); - sslConfig.setPrivateKey(QSslKey(m_Im.getPrivateKey(), QSsl::Rsa)); - request.setSslConfiguration(sslConfig); + request.setSslConfiguration(m_Im.getSslConfig()); QNetworkReply* reply = m_Nam.get(request);