mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
Allow adding CA chain to cert files
This commit is contained in:
parent
e5cdd853d4
commit
39e2f5a375
@ -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);
|
||||
|
||||
@ -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<QSslCertificate> 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<ql.size();++i) {
|
||||
const QSslCertificate &c = ql.at(i);
|
||||
if (isKeyForCert(qskKey, c)) {
|
||||
qscCert = c;
|
||||
ql.removeAt(i);
|
||||
}
|
||||
}
|
||||
qlCA = ql;
|
||||
}
|
||||
|
||||
if (! crt.isEmpty()) {
|
||||
qscCert = QSslCertificate(crt);
|
||||
if (qscCert.isNull()) {
|
||||
log("Failed to parse certificate.");
|
||||
} else if (qscCert.issuerInfo(QSslCertificate::CommonName) == QLatin1String("Murmur Autogenerated Certificate")) {
|
||||
if (qscCert.issuerInfo(QSslCertificate::CommonName) == QLatin1String("Murmur Autogenerated Certificate")) {
|
||||
log("Old autogenerated certificate is unusable for registration, invalidating it");
|
||||
qscCert = QSslCertificate();
|
||||
}
|
||||
}
|
||||
|
||||
if (! key.isEmpty() && qscCert.isNull()) {
|
||||
qscCert = QSslCertificate(key);
|
||||
if (! qscCert.isNull()) {
|
||||
log("Using certificate from key.");
|
||||
}
|
||||
}
|
||||
|
||||
if (! qscCert.isNull()) {
|
||||
QSsl::KeyAlgorithm alg = qscCert.publicKey().algorithm();
|
||||
|
||||
if (! key.isEmpty()) {
|
||||
qskKey = QSslKey(key, alg, QSsl::Pem, QSsl::PrivateKey, pass);
|
||||
if (qskKey.isNull()) {
|
||||
log("Failed to parse key.");
|
||||
}
|
||||
}
|
||||
|
||||
if (! crt.isEmpty() && qskKey.isNull()) {
|
||||
qskKey = QSslKey(crt, alg, QSsl::Pem, QSsl::PrivateKey, pass);
|
||||
if (! qskKey.isNull()) {
|
||||
log("Using key from certificate.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (qscCert.isNull() || qskKey.isNull()) {
|
||||
@ -107,7 +132,7 @@ void Server::initializeCert() {
|
||||
|
||||
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);
|
||||
@ -142,21 +167,11 @@ void Server::initializeCert() {
|
||||
qskKey = QSslKey(key, QSsl::Rsa, QSsl::Der);
|
||||
if (qskKey.isNull())
|
||||
log("Key generation failed");
|
||||
|
||||
|
||||
setConf("certificate", qscCert.toPem());
|
||||
setConf("key", qskKey.toPem());
|
||||
}
|
||||
}
|
||||
|
||||
QList<QSslCipher> 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 {
|
||||
|
||||
@ -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<QSslCertificate> 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<QSslCertificate> ql = QSslCertificate::fromData(crt);
|
||||
ql << QSslCertificate::fromData(key);
|
||||
for (int i=0;i<ql.size(); ++i) {
|
||||
const QSslCertificate &c = ql.at(i);
|
||||
if (Server::isKeyForCert(qskKey, c)) {
|
||||
qscCert = c;
|
||||
ql.removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (qscCert.isNull()) {
|
||||
qFatal("Failed to find certificate matching private key.");
|
||||
}
|
||||
if (ql.length() > 0) {
|
||||
QSslSocket::addDefaultCaCertificates(ql);
|
||||
qCritical("Adding %d CA certificates from certificate file.", ql.length());
|
||||
}
|
||||
}
|
||||
|
||||
if (! QSslSocket::supportsSsl()) {
|
||||
qFatal("Qt without SSL Support");
|
||||
}
|
||||
|
||||
QList<QSslCipher> 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);
|
||||
|
||||
@ -591,6 +591,7 @@ void Server::newClient() {
|
||||
|
||||
sock->setPrivateKey(qskKey);
|
||||
sock->setLocalCertificate(qscCert);
|
||||
sock->addCaCertificates(qlCA);
|
||||
|
||||
if (qqIds.isEmpty()) {
|
||||
sock->disconnectFromHost();
|
||||
|
||||
@ -150,9 +150,9 @@ class Server : public QThread {
|
||||
QRegExp qrUserName;
|
||||
QRegExp qrChannelName;
|
||||
|
||||
QList<QSslCertificate> 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;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user