From 39e2f5a375cdb80cb53d2dbd660ac6fe4eb0699e Mon Sep 17 00:00:00 2001 From: Thorvald Natvig Date: Fri, 22 May 2009 15:47:20 +0200 Subject: [PATCH] Allow adding CA chain to cert files --- src/mumble/Cert.cpp | 2 +- src/murmur/Cert.cpp | 111 ++++++++++++++++++++++++------------------ src/murmur/Meta.cpp | 90 ++++++++++++++++++++++------------ src/murmur/Server.cpp | 1 + src/murmur/Server.h | 3 +- 5 files changed, 125 insertions(+), 82 deletions(-) diff --git a/src/mumble/Cert.cpp b/src/mumble/Cert.cpp index 9a68789ee..059057988 100644 --- a/src/mumble/Cert.cpp +++ b/src/mumble/Cert.cpp @@ -375,7 +375,7 @@ Settings::KeyPair CertWizard::generateNewCert(QString qsname, const QString &qse X509 *x509 = X509_new(); EVP_PKEY *pkey = EVP_PKEY_new(); - RSA *rsa = RSA_generate_key(1024,RSA_F4,NULL,NULL); + RSA *rsa = RSA_generate_key(2048,RSA_F4,NULL,NULL); EVP_PKEY_assign_RSA(pkey, rsa); X509_set_version(x509, 2); diff --git a/src/murmur/Cert.cpp b/src/murmur/Cert.cpp index b16e1677c..618298aec 100644 --- a/src/murmur/Cert.cpp +++ b/src/murmur/Cert.cpp @@ -47,51 +47,76 @@ static int add_ext(X509 * crt, int nid, char *value) { return 1; } +bool Server::isKeyForCert(const QSslKey &key, const QSslCertificate &cert) { + if (key.isNull() || cert.isNull() || (key.type() != QSsl::PrivateKey)) + return false; + + QByteArray qbaKey = key.toDer(); + QByteArray qbaCert = cert.toDer(); + + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + BIO *mem = NULL; + + mem = BIO_new_mem_buf(qbaKey.data(), qbaKey.size()); + BIO_set_close(mem, BIO_NOCLOSE); + pkey = d2i_PrivateKey_bio(mem, NULL); + BIO_free(mem); + + mem = BIO_new_mem_buf(qbaCert.data(), qbaCert.size()); + BIO_set_close(mem, BIO_NOCLOSE); + x509 = d2i_X509_bio(mem, NULL); + BIO_free(mem); + mem = NULL; + + if (x509 && pkey && X509_check_private_key(x509, pkey)) { + EVP_PKEY_free(pkey); + X509_free(x509); + return true; + } + + if (pkey) + EVP_PKEY_free(pkey); + if (x509) + X509_free(x509); + return false; +} + void Server::initializeCert() { QByteArray crt, key, pass; - if (! QSslSocket::supportsSsl()) { - qFatal("Qt without SSL Support"); - } - crt = getConf("certificate", QString()).toByteArray(); key = getConf("key", QString()).toByteArray(); pass = getConf("passphrase", QByteArray()).toByteArray(); + + QList ql; + + if (! key.isEmpty()) { + qskKey = QSslKey(key, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, pass); + if (qskKey.isNull()) + qskKey = QSslKey(key, QSsl::Dsa, QSsl::Pem, QSsl::PrivateKey, pass); + } + if (qskKey.isNull() && ! crt.isEmpty()) { + qskKey = QSslKey(crt, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, pass); + if (qskKey.isNull()) + qskKey = QSslKey(crt, QSsl::Dsa, QSsl::Pem, QSsl::PrivateKey, pass); + } + if (! qskKey.isNull()) { + ql << QSslCertificate::fromData(crt); + ql << QSslCertificate::fromData(key); + for(int i=0;i pref; - foreach(QSslCipher c, QSslSocket::defaultCiphers()) { - if (c.usedBits() < 128) - continue; - pref << c; - } - if (pref.isEmpty()) - qFatal("No ciphers of at least 128 bit found"); - QSslSocket::setDefaultCiphers(pref); } const QString Server::getDigest() const { diff --git a/src/murmur/Meta.cpp b/src/murmur/Meta.cpp index b349d9bad..1f4cf367c 100644 --- a/src/murmur/Meta.cpp +++ b/src/murmur/Meta.cpp @@ -199,9 +199,26 @@ void MetaParams::read(QString fname) { QString qsSSLCert = qs.value("sslCert").toString(); QString qsSSLKey = qs.value("sslKey").toString(); + QString qsSSLCA = qs.value("sslCA").toString(); qbaPassPhrase = qs.value("sslPassPhrase").toByteArray(); + if (! qsSSLCA.isEmpty()) { + QFile pem(qsSSLCA); + if (pem.open(QIODevice::ReadOnly)) { + QByteArray qba = pem.readAll(); + pem.close(); + QList ql = QSslCertificate::fromData(qba); + if (ql.isEmpty()) { + qCritical("Failed to parse any CA certificates from %s", qPrintable(qsSSLCA)); + } else { + QSslSocket::addDefaultCaCertificates(ql); + } + } else { + qCritical("Failed to read %s", qPrintable(qsSSLCert)); + } + } + QByteArray crt, key; if (! qsSSLCert.isEmpty()) { @@ -223,46 +240,55 @@ void MetaParams::read(QString fname) { } } - if (! crt.isEmpty()) { - qscCert = QSslCertificate(crt); - if (qscCert.isNull()) { - qCritical("Failed to parse certificate."); - } - } - - if (! key.isEmpty() && qscCert.isNull()) { - qscCert = QSslCertificate(key); - if (! qscCert.isNull()) { - qWarning("Using certificate from key file."); - } - } - - if (! qscCert.isNull()) { - QSsl::KeyAlgorithm alg = qscCert.publicKey().algorithm(); - + if (! key.isEmpty() || ! crt.isEmpty()) { if (! key.isEmpty()) { - qskKey = QSslKey(key, alg, QSsl::Pem, QSsl::PrivateKey, qbaPassPhrase); - if (qskKey.isNull()) { - qCritical("Failed to parse key file."); - } + qskKey = QSslKey(key, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, qbaPassPhrase); + if (qskKey.isNull()) + qskKey = QSslKey(key, QSsl::Dsa, QSsl::Pem, QSsl::PrivateKey, qbaPassPhrase); } - - if (! crt.isEmpty() && qskKey.isNull()) { - qskKey = QSslKey(crt, alg, QSsl::Pem, QSsl::PrivateKey, qbaPassPhrase); - if (! qskKey.isNull()) { - qWarning("Using key from certificate file."); - } + if (qskKey.isNull() && ! crt.isEmpty()) { + qskKey = QSslKey(crt, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, qbaPassPhrase); + if (qskKey.isNull()) + qskKey = QSslKey(crt, QSsl::Dsa, QSsl::Pem, QSsl::PrivateKey, qbaPassPhrase); + if (! qskKey.isNull()) + qCritical("Using private key found in certificate file."); } if (qskKey.isNull()) - qscCert = QSslCertificate(); - } + qFatal("No private key found in certificate or key file."); - if (qscCert.isNull() || qskKey.isNull()) { - if (! key.isEmpty() || ! crt.isEmpty()) { - qFatal("Certificate specified, but failed to load."); + QList ql = QSslCertificate::fromData(crt); + ql << QSslCertificate::fromData(key); + for (int i=0;i 0) { + QSslSocket::addDefaultCaCertificates(ql); + qCritical("Adding %d CA certificates from certificate file.", ql.length()); } } + if (! QSslSocket::supportsSsl()) { + qFatal("Qt without SSL Support"); + } + + QList pref; + foreach(QSslCipher c, QSslSocket::defaultCiphers()) { + if (c.usedBits() < 128) + continue; + pref << c; + } + if (pref.isEmpty()) + qFatal("No SSL ciphers of at least 128 bit found"); + QSslSocket::setDefaultCiphers(pref); + qmConfig.clear(); qmConfig.insert(QLatin1String("host"),qhaBind.toString()); qmConfig.insert(QLatin1String("password"),qsPassword); diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index a1f2dd8bc..d04ebfdb2 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -591,6 +591,7 @@ void Server::newClient() { sock->setPrivateKey(qskKey); sock->setLocalCertificate(qscCert); + sock->addCaCertificates(qlCA); if (qqIds.isEmpty()) { sock->disconnectFromHost(); diff --git a/src/murmur/Server.h b/src/murmur/Server.h index 71a3c5299..60980033b 100644 --- a/src/murmur/Server.h +++ b/src/murmur/Server.h @@ -150,9 +150,9 @@ class Server : public QThread { QRegExp qrUserName; QRegExp qrChannelName; + QList qlCA; QSslCertificate qscCert; QSslKey qskKey; - QByteArray qbaPassPhrase; bool bValid; @@ -171,6 +171,7 @@ class Server : public QThread { // Certificate stuff, implemented partially in Cert.cpp public: + static bool isKeyForCert(const QSslKey &key, const QSslCertificate &cert); void initializeCert(); const QString getDigest() const;