summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/ssl')
-rw-r--r--src/network/ssl/qsslsocket.cpp42
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp35
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp3
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h1
-rw-r--r--src/network/ssl/qsslsocket_p.h5
5 files changed, 72 insertions, 14 deletions
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 4252123..61f27fe 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -143,6 +143,15 @@
setDefaultCaCertificates().
\endlist
+ \note If available, root certificates on Unix (excluding Mac OS X) will be
+ loaded on demand from the standard certificate directories. If
+ you do not want to load root certificates on demand, you need to call either
+ the static function setDefaultCaCertificates() before the first SSL handshake
+ is made in your application, (e.g. via
+ "QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates());"),
+ or call setCaCertificates() on your QSslSocket instance prior to the SSL
+ handshake.
+
For more information about ciphers and certificates, refer to QSslCipher and
QSslCertificate.
@@ -1249,6 +1258,7 @@ void QSslSocket::setCaCertificates(const QList<QSslCertificate> &certificates)
{
Q_D(QSslSocket);
d->configuration.caCertificates = certificates;
+ d->allowRootCertOnDemandLoading = false;
}
/*!
@@ -1258,6 +1268,9 @@ void QSslSocket::setCaCertificates(const QList<QSslCertificate> &certificates)
handshake with addCaCertificate(), addCaCertificates(), and
setCaCertificates().
+ \note On Unix, this method may return an empty list if the root
+ certificates are loaded on demand.
+
\sa addCaCertificate(), addCaCertificates(), setCaCertificates()
*/
QList<QSslCertificate> QSslSocket::caCertificates() const
@@ -1311,10 +1324,9 @@ void QSslSocket::addDefaultCaCertificates(const QList<QSslCertificate> &certific
/*!
Sets the default CA certificate database to \a certificates. The
default CA certificate database is originally set to your system's
- default CA certificate database. If no system default database is
- found, Qt will provide its own default database. You can override
- the default CA certificate database with your own CA certificate
- database using this function.
+ default CA certificate database. You can override the default CA
+ certificate database with your own CA certificate database using
+ this function.
Each SSL socket's CA certificate database is initialized to the
default CA certificate database.
@@ -1336,6 +1348,9 @@ void QSslSocket::setDefaultCaCertificates(const QList<QSslCertificate> &certific
Each SSL socket's CA certificate database is initialized to the
default CA certificate database.
+ \note On Unix, this method may return an empty list if the root
+ certificates are loaded on demand.
+
\sa caCertificates()
*/
QList<QSslCertificate> QSslSocket::defaultCaCertificates()
@@ -1803,6 +1818,7 @@ QSslSocketPrivate::QSslSocketPrivate()
, connectionEncrypted(false)
, ignoreAllSslErrors(false)
, readyReadEmittedPointer(0)
+ , allowRootCertOnDemandLoading(true)
, plainSocket(0)
{
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
@@ -1879,6 +1895,7 @@ void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciph
*/
QList<QSslCertificate> QSslSocketPrivate::defaultCaCertificates()
{
+ // ### Qt5: rename everything containing "caCertificates" to "rootCertificates" or similar
QSslSocketPrivate::ensureInitialized();
QMutexLocker locker(&globalData()->mutex);
return globalData()->config->caCertificates;
@@ -1893,6 +1910,9 @@ void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &c
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates = certs;
+ // when the certificates are set explicitly, we do not want to
+ // load the system certificates on demand
+ s_loadRootCertsOnDemand = false;
}
/*!
@@ -2192,6 +2212,20 @@ void QSslSocketPrivate::_q_flushReadBuffer()
transmit();
}
+/*!
+ \internal
+*/
+QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
+{
+ return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva, MeeGo ...
+ << "/usr/lib/ssl/certs/" // Gentoo, Mandrake
+ << "/usr/share/ssl/" // Centos, Redhat, SuSE
+ << "/usr/local/ssl/" // Normal OpenSSL Tarball
+ << "/var/ssl/certs/" // AIX
+ << "/usr/local/ssl/certs/" // Solaris
+ << "/opt/openssl/certs/"; // HP-UX
+}
+
QT_END_NAMESPACE
// For private slots
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 7d21bd3..83714ed 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -80,6 +80,7 @@ QT_BEGIN_NAMESPACE
bool QSslSocketPrivate::s_libraryLoaded = false;
bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
+bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
/* \internal
@@ -317,6 +318,13 @@ init_context:
q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
}
+ if (s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
+ // tell OpenSSL the directories where to look up the root certs on demand
+ QList<QByteArray> unixDirs = unixRootCertDirectories();
+ for (int a = 0; a < unixDirs.count(); ++a)
+ q_SSL_CTX_load_verify_locations(ctx, 0, unixDirs.at(a).constData());
+ }
+
// Register a custom callback to get all verification errors.
X509_STORE_set_verify_cb_func(ctx->cert_store, q_X509Callback);
@@ -517,8 +525,22 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
} else {
qWarning("could not load crypt32 library"); // should never happen
}
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) && !defined(Q_OS_MAC)
+ // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
+ QList<QByteArray> dirs = unixRootCertDirectories();
+ QStringList symLinkFilter;
+ symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
+ for (int a = 0; a < dirs.count(); ++a) {
+ QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
+ if (iterator.hasNext()) {
+ s_loadRootCertsOnDemand = true;
+ break;
+ }
+ }
#endif
- setDefaultCaCertificates(systemCaCertificates());
+ // if on-demand loading was not enabled, load the certs now
+ if (!s_loadRootCertsOnDemand)
+ setDefaultCaCertificates(systemCaCertificates());
}
/*!
@@ -780,6 +802,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der));
}
}
+ CFRelease(cfCerts);
}
else {
// no detailed error handling here
@@ -813,15 +836,7 @@ QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
}
#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
QSet<QString> certFiles;
- QList<QByteArray> directories;
- directories << "/etc/ssl/certs/"; // (K)ubuntu, OpenSUSE, Mandriva, MeeGo ...
- directories << "/usr/lib/ssl/certs/"; // Gentoo, Mandrake
- directories << "/usr/share/ssl/"; // Centos, Redhat, SuSE
- directories << "/usr/local/ssl/"; // Normal OpenSSL Tarball
- directories << "/var/ssl/certs/"; // AIX
- directories << "/usr/local/ssl/certs/"; // Solaris
- directories << "/opt/openssl/certs/"; // HP-UX
-
+ QList<QByteArray> directories = unixRootCertDirectories();
QDir currentDir;
QStringList nameFilters;
nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 38598b6..b9a05f3 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -262,6 +262,7 @@ DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c,
#endif
DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
#ifdef Q_OS_SYMBIAN
#define RESOLVEFUNC(func, ordinal, lib) \
@@ -630,6 +631,7 @@ bool q_resolveOpenSslSymbols()
#endif
RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf, 1153, libs.second )
RESOLVEFUNC(OPENSSL_add_all_algorithms_conf, 1152, libs.second )
+ RESOLVEFUNC(SSL_CTX_load_verify_locations, 34, libs.second )
#else // Q_OS_SYMBIAN
#ifdef SSLEAY_MACROS
RESOLVEFUNC(ASN1_dup)
@@ -754,6 +756,7 @@ bool q_resolveOpenSslSymbols()
#endif
RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf)
RESOLVEFUNC(OPENSSL_add_all_algorithms_conf)
+ RESOLVEFUNC(SSL_CTX_load_verify_locations)
#endif // Q_OS_SYMBIAN
symbolsResolved = true;
delete libs.first;
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index 954ffba..c05dfe11 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -412,6 +412,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#endif
void q_OPENSSL_add_all_algorithms_noconf();
void q_OPENSSL_add_all_algorithms_conf();
+int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);
// Helper function
class QDateTime;
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
index 3a14488..7b92f95 100644
--- a/src/network/ssl/qsslsocket_p.h
+++ b/src/network/ssl/qsslsocket_p.h
@@ -112,6 +112,8 @@ public:
// that was used for connecting to.
QString verificationPeerName;
+ bool allowRootCertOnDemandLoading;
+
static bool supportsSsl();
static void ensureInitialized();
static void deinitialize();
@@ -168,6 +170,9 @@ private:
static bool s_libraryLoaded;
static bool s_loadedCiphersAndCerts;
+protected:
+ static bool s_loadRootCertsOnDemand;
+ static QList<QByteArray> unixRootCertDirectories();
};
QT_END_NAMESPACE