Using SSL client certificate
-
wrote on 7 Oct 2013, 18:01 last edited by
Hello all,
I would like to communicate with a webservice which requires client side certificate based authentication.
The certificate comes in PKCS12# format.I have been able to extract the client certificate using openssl:
@openssl pkcs12 -in 24d5bfcdbd55623894351e0dcdd6aee4f1a04a3d -clcerts -out x509.pem@My test code can be found below which reads the extracted certificate and tries to connect to the server:
@QFile certFile("/home/mm/Projektek/qt/qtrafik/soap/certs/x509");
certFile.open(QFile::ReadOnly);
QSslCertificate cert(&certFile);
certFile.close();qWarning() << cert.expiryDate() << cert.version() << cert.serialNumber() << cert.isNull() << cert.issuerInfo(QSslCertificate::Organization); qWarning() << cert.toText(); QSslConfiguration configuration; configuration.setLocalCertificate(cert); qWarning() << configuration.localCertificate().serialNumber(); QNetworkRequest request; request.setSslConfiguration(configuration); request.setUrl(QUrl("https://adatkuldes-teszt.nemzetidohany.gov.hu:8444/nd/MasterData.svc?wsdl")); reply = manager->get(request); connect(reply, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>))); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), this, SLOT(finished()));@
The loaded certificate information (cert.toText();) correlates 100% with the certificate details in the Firefox (I have been able to load the cert to my browser and access the server).
Unfortunatelly my QNetworkManager emits the error(QNetworkReply::NetworkError) signal with 99 (QNetworkReply::UnknownNetworkError) error code with "Unable to init SSL Context: " errorString().
I am working with Qt 5.0.1 on kUbuntu 13.04 64 bit.
I have openssl installed, and the QSslSocket::supportsSsl() returns true.Any help, suggestion or hint will be highly appericiated!
-
wrote on 9 Oct 2013, 18:15 last edited by
I have compiled my test project with Qt 4.8.4, and it resulted a different error message:
@Cannot provide a certificate with no key, @
After some searching I realized that I have to extract the CA cert, and the private key from my PKCS12# file with openssl, and load them to my QSslConfiguration.
To save it to the posterity this is how it is working for me now:
@
openssl pkcs12 -in 24d5bfcdbd55623894351e0dcdd6aee4f1a04a3d -clcerts -out clientcert.pem
openssl pkcs12 -in 24d5bfcdbd55623894351e0dcdd6aee4f1a04a3d -nocerts -out privkey.key
openssl pkcs12 -in 24d5bfcdbd55623894351e0dcdd6aee4f1a04a3d -cacerts -out cacert.pem
@At the extraction of the private key I have given 1234 as password (see the code below.)
@ QSslConfiguration configuration;
QFile certFile("/home/mm/Projektek/qt/qtrafik/soap/certs/clientcert.pem"); certFile.open(QFile::ReadOnly); QSslCertificate cert(&certFile); certFile.close(); configuration.setLocalCertificate(cert); QList<QSslCertificate> certs; certFile.setFileName("/home/mm/Projektek/qt/qtrafik/soap/certs/cacert.pem"); certFile.open(QFile::ReadOnly); QSslCertificate caCert(&certFile); certFile.close(); certs.append(caCert); configuration.setCaCertificates(certs); QFile keyFile("/home/mm/Projektek/qt/qtrafik/soap/certs/privkey.key"); keyFile.open(QFile::ReadOnly); QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "1234"); qWarning() << key.isNull(); configuration.setPrivateKey(key); keyFile.close(); QNetworkRequest request; request.setSslConfiguration(configuration); request.setUrl(QUrl("https://adatkuldes-teszt.nemzetidohany.gov.hu:8444/nd/MasterData.svc?wsdl")); reply = manager->get(request); connect(reply, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>))); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), this, SLOT(finished()));@
-
wrote on 11 Jan 2014, 13:47 last edited by
I have been able to create a more sophisticated solution using the QCA (Qt cryptographics architecture see: http://delta.affinix.com/qca/). To be able to use it with Qt5 download the latest version of the code from here:
git://anongit.kde.org/qca.gitMy SSL configuration initialization code is the following:
@//initialize QCA
QCA::init();if (QFile::exists(m_certificatePath)) { QCA::KeyBundle bundle(m_certificatePath, QCA::SecureArray(m_certificatePassword.toLocal8Bit())); QList<QSslCertificate> CACerts; foreach (QCA::Certificate cert, bundle.certificateChain()) { if (cert.isCA()) { QSslCertificate CACertificate(cert.toPEM().toLocal8Bit(), QSsl::Pem); CACerts.append(CACertificate); } else { m_SSLConfiguration.setLocalCertificate(QSslCertificate(cert.toPEM().toLocal8Bit(), QSsl::Pem)); } } m_SSLConfiguration.setCaCertificates(CACerts); QSslKey key(bundle.privateKey().toDER().toByteArray(), QSsl::Rsa, QSsl::Der); m_SSLConfiguration.setPrivateKey(key); }@
The application have to be linked with the QCA libraries (-lqca) and the Qt library search path have to contain the "crypto" folder of the compiled QCA library.
-
wrote on 7 Jan 2016, 21:11 last edited by
here is a clean way i used without a 3rd party lib.
bool loadPfxCertifcate(QString certFilename, QString passphrase) { QFile certFile(certFilename); certFile.open(QFile::ReadOnly); QSslCertificate certificate; QSslKey key; QList<QSslCertificate> importedCerts; bool imported = QSslCertificate::importPkcs12(&certFile, &key, &certificate, &importedCerts, QByteArray::fromStdString(passphrase.toStdString())); certFile.close(); qDebug() << "Imported cert:" << imported; if (imported) { QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); QList<QSslCertificate> certs = sslConfig.caCertificates(); QList<QSslCertificate> localCerts = sslConfig.localCertificateChain(); localCerts.append(certificate); certs.append(importedCerts); sslConfig.setLocalCertificateChain(localCerts); sslConfig.setCaCertificates(certs); sslConfig.setPrivateKey(key); QSslConfiguration::setDefaultConfiguration(sslConfig); } return imported; }