Allow adding CA chain to cert files

This commit is contained in:
Thorvald Natvig 2009-05-22 15:47:20 +02:00
parent e5cdd853d4
commit 39e2f5a375
5 changed files with 125 additions and 82 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -591,6 +591,7 @@ void Server::newClient() {
sock->setPrivateKey(qskKey);
sock->setLocalCertificate(qscCert);
sock->addCaCertificates(qlCA);
if (qqIds.isEmpty()) {
sock->disconnectFromHost();

View File

@ -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;