GH-1202 rebuild SSL certs on start on OSX
This commit is contained in:
parent
12b14c3400
commit
22c0d5cf46
@ -322,6 +322,15 @@ set(MULTIMC_QRCS
|
|||||||
resources/certs/certs.qrc
|
resources/certs/certs.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(MultiMC_OSX_source
|
||||||
|
CertWorkaround.cpp
|
||||||
|
CertWorkaround.h
|
||||||
|
)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
list(APPEND MULTIMC_SOURCES ${MultiMC_OSX_source})
|
||||||
|
endif()
|
||||||
|
|
||||||
######## Windows resource files ########
|
######## Windows resource files ########
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(MULTIMC_RCS resources/multimc.rc)
|
set(MULTIMC_RCS resources/multimc.rc)
|
||||||
|
120
application/CertWorkaround.cpp
Normal file
120
application/CertWorkaround.cpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include <stdexcept>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QSslSocket>
|
||||||
|
|
||||||
|
#include <Security/Security.h>
|
||||||
|
|
||||||
|
// CFRelease will crash if passed NULL
|
||||||
|
#define SafeCFRelease(ref) \
|
||||||
|
if (ref) \
|
||||||
|
CFRelease(ref);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief LoadCertificatesFromKeyChain Load all certificates from the KeyChain path provided
|
||||||
|
* and return them as
|
||||||
|
* QSslCertificates.
|
||||||
|
* \param keyChainPath The KeyChain path. Pass an empty string to use the
|
||||||
|
* user's keychain.
|
||||||
|
* \return A list of new QSslCertificates generated from the
|
||||||
|
* KeyChain DER data.
|
||||||
|
*/
|
||||||
|
static QList<QSslCertificate> LoadCertificatesFromKeyChain(const std::string &keyChainPath = std::string())
|
||||||
|
{
|
||||||
|
QList<QSslCertificate> qtCerts;
|
||||||
|
|
||||||
|
SecKeychainRef certsKeyChain = NULL;
|
||||||
|
SecKeychainSearchRef searchItem = NULL;
|
||||||
|
SecKeychainItemRef itemRef = NULL;
|
||||||
|
CSSM_DATA certData = {0, 0};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OSStatus status = errSecSuccess;
|
||||||
|
|
||||||
|
// if a keychain path was provided, obtain a pointer
|
||||||
|
if (!keyChainPath.empty())
|
||||||
|
{
|
||||||
|
status = SecKeychainOpen(keyChainPath.c_str(), &certsKeyChain);
|
||||||
|
if (status != errSecSuccess)
|
||||||
|
{
|
||||||
|
throw status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a search query reference for certificates
|
||||||
|
status = SecKeychainSearchCreateFromAttributes(certsKeyChain, kSecCertificateItemClass,
|
||||||
|
NULL, &searchItem);
|
||||||
|
if (status != errSecSuccess)
|
||||||
|
{
|
||||||
|
throw status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop through the certificates
|
||||||
|
while (SecKeychainSearchCopyNext(searchItem, &itemRef) != errSecItemNotFound)
|
||||||
|
{
|
||||||
|
// copy the KeyChain item data into a CSSM_DATA struct - this will be the certs Der
|
||||||
|
// data
|
||||||
|
status = SecKeychainItemCopyContent(itemRef, NULL, NULL,
|
||||||
|
reinterpret_cast<UInt32 *>(&certData.Length),
|
||||||
|
reinterpret_cast<void **>(&certData.Data));
|
||||||
|
|
||||||
|
if (status != errSecSuccess)
|
||||||
|
{
|
||||||
|
throw status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a Qt byte array from the data - the data is NOT copied
|
||||||
|
const QByteArray byteArray = QByteArray::fromRawData(
|
||||||
|
reinterpret_cast<const char *>(certData.Data), certData.Length);
|
||||||
|
|
||||||
|
// create a Qt certificate from the data and add it to the list
|
||||||
|
QSslCertificate qtCert(byteArray, QSsl::Der);
|
||||||
|
std::cout << "COMMON NAME: "
|
||||||
|
<< qtCert.issuerInfo(QSslCertificate::CommonName).toStdString().c_str()
|
||||||
|
<< " ORG NAME: "
|
||||||
|
<< qtCert.issuerInfo(QSslCertificate::Organization).toStdString().c_str()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
qtCerts << qtCert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OSStatus status)
|
||||||
|
{
|
||||||
|
CFStringRef errorMessage = SecCopyErrorMessageString(status, NULL);
|
||||||
|
std::cerr << CFStringGetCStringPtr(errorMessage, kCFStringEncodingMacRoman)
|
||||||
|
<< std::endl;
|
||||||
|
SafeCFRelease(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
SecKeychainItemFreeContent(NULL, certData.Data);
|
||||||
|
SafeCFRelease(itemRef);
|
||||||
|
SafeCFRelease(searchItem);
|
||||||
|
SafeCFRelease(certsKeyChain);
|
||||||
|
|
||||||
|
return qtCerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RebuildQtCertificates()
|
||||||
|
{
|
||||||
|
const QList<QSslCertificate> existingCerts = QSslSocket::defaultCaCertificates();
|
||||||
|
QList<QSslCertificate> certs = LoadCertificatesFromKeyChain();
|
||||||
|
certs += LoadCertificatesFromKeyChain(
|
||||||
|
"/System/Library/Keychains/SystemRootCertificates.keychain");
|
||||||
|
|
||||||
|
Q_FOREACH (const QSslCertificate qtCert, certs)
|
||||||
|
{
|
||||||
|
if (!existingCerts.contains(qtCert))
|
||||||
|
{
|
||||||
|
std::cout << "cert not known to Qt - adding" << std::endl;
|
||||||
|
std::cout << "COMMON NAME: "
|
||||||
|
<< qtCert.issuerInfo(QSslCertificate::CommonName).toStdString().c_str()
|
||||||
|
<< " ORG NAME: "
|
||||||
|
<< qtCert.issuerInfo(QSslCertificate::Organization).toStdString().c_str()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
QSslSocket::addDefaultCaCertificate(qtCert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
application/CertWorkaround.h
Normal file
3
application/CertWorkaround.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void RebuildQtCertificates();
|
@ -283,10 +283,15 @@ MultiMC::~MultiMC()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
#include "CertWorkaround.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
void MultiMC::initSSL()
|
void MultiMC::initSSL()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
Q_INIT_RESOURCE(certs);
|
Q_INIT_RESOURCE(certs);
|
||||||
|
RebuildQtCertificates();
|
||||||
QFile equifaxFile(":/certs/Equifax_Secure_Certificate_Authority.pem");
|
QFile equifaxFile(":/certs/Equifax_Secure_Certificate_Authority.pem");
|
||||||
equifaxFile.open(QIODevice::ReadOnly);
|
equifaxFile.open(QIODevice::ReadOnly);
|
||||||
QSslCertificate equifaxCert(equifaxFile.readAll(), QSsl::Pem);
|
QSslCertificate equifaxCert(equifaxFile.readAll(), QSsl::Pem);
|
||||||
|
Loading…
Reference in New Issue
Block a user