Mercurial > trustbridge
view ui/sslconnection_curl.cpp @ 1012:a80abef948fa
(issue86) Initialize NSS db with empty pin in case it needs it.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 02 Sep 2014 15:20:24 +0200 |
parents | 7dff5c0c569c |
children | fe2c6666b462 |
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "sslconnection_curl.h" #include <polarssl/ssl.h> #include <QSaveFile> #undef CONNECTION_DEBUG SSLConnectionCurl::SSLConnectionCurl(const QString& url, const QByteArray& certificate): SSLConnection (url, certificate), mCurl (NULL) { curl_global_init(CURL_GLOBAL_DEFAULT); mCurl = curl_easy_init(); if (!mCurl) { qDebug() << "Failed to initialize curl"; return; } #ifdef RELEASE_BUILD if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 1L) != CURLE_OK) { #else /* For testing we do not have to trust the issuer. This should not * be dangerous as we pin the peer certificate directly. */ if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 0L) != CURLE_OK) { #endif /* Should be default anyway */ qDebug() << "Setting verifypeer failed"; return; } #ifdef RELEASE_BUILD if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYHOST, 1L) != CURLE_OK) { #else /* For testing we do not have to trust host. This should not * be dangerous as we pin the peer certificate directly. */ if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYHOST, 0L) != CURLE_OK) { #endif /* Should be default anyway */ qDebug() << "Setting verifypeer failed"; return; } if (curl_easy_setopt(mCurl, CURLOPT_ERRORBUFFER, mErrBuf) != CURLE_OK) { qDebug() << "Setting errorbuf failed"; return; } #ifdef RELEASE_BUILD if (curl_easy_setopt(mCurl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2) != CURLE_OK) { qDebug() << "Setting ssl version failed."; return; } #endif mCertFile.open(); if (mCertFile.write(mPinnedCert) != mPinnedCert.size()) { qDebug() << "Failed to write temporary certificate"; return; } mCertFile.close(); if (curl_easy_setopt(mCurl, CURLOPT_CAINFO, mCertFile.fileName().toUtf8().constData()) != CURLE_OK) { qDebug() << "Failed to set ca certificate"; return; } /* If the build fails here maybe you probably forgot to apply the * trustbridge patches to curl */ if (curl_easy_setopt(mCurl, CURLOPT_PEERCERT, mCertFile.fileName().toUtf8().constData()) != CURLE_OK) { qDebug() << "Failed set peer certificate."; return; } mInitialized = true; #ifdef CONNECTION_DEBUG curl_easy_setopt(mCurl, CURLOPT_VERBOSE, 1L); #endif } SSLConnectionCurl::~SSLConnectionCurl() { if (mCurl) { curl_easy_cleanup (mCurl); } if (mInitialized) { mCertFile.close(); } curl_global_cleanup(); } int SSLConnectionCurl::connect() { CURLcode retval; if (curl_easy_setopt(mCurl, CURLOPT_URL, mUrl.toEncoded().constData()) != CURLE_OK) { qDebug() << "Failed to set URL"; return -1; } if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 1L) != CURLE_OK) { qDebug() << "Failed to set connect only option"; return -1; } retval = curl_easy_perform(mCurl); if (retval != CURLE_OK) { qDebug() << "Failed to connect: " << mErrBuf << " retval: " << retval; if (retval == CURLE_PEER_FAILED_VERIFICATION) { mErrorState = InvalidCertificate; return -1; } if (retval == CURLE_SSL_CONNECT_ERROR) { mErrorState = SSLHandshakeFailed; return -1; } mErrorState = NoConnection; return -1; } mConnected = true; return 0; } /* Globally do this as we can't pass "this" (the ptr) to the c function */ size_t ssl_curl_max_write, ssl_curl_written; size_t write_data(void *ptr, size_t size, size_t nmemb, QSaveFile *fp) { qDebug() << "Writing size: " << size << " * " << nmemb; if (ssl_curl_max_write < ssl_curl_written) { qDebug() << "Aborting write. Too much data."; return 0; } size_t written = fp->write((const char *)ptr, size * nmemb); if (written != size * nmemb) { qDebug() << "Failed to write data. Written: " << written << " requested: " << size * nmemb; return 0; } ssl_curl_written += written; return written; } bool SSLConnectionCurl::downloadFile(const QString &resource, const QString &fileName, size_t maxSize) { ssl_curl_written = 0; ssl_curl_max_write = maxSize; QSaveFile outputFile(fileName); // Open / Create the file to write to. if (!outputFile.open(QIODevice::WriteOnly)) { qDebug() << "Failed to open file"; return false; } QUrl urlCopy = mUrl; urlCopy.setPath(resource); if (curl_easy_setopt(mCurl, CURLOPT_URL, urlCopy.toEncoded().constData()) != CURLE_OK) { qDebug() << "Failed to set URL"; return false; } if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 0L) != CURLE_OK) { qDebug() << "Failed to set connect"; return false; } if (curl_easy_setopt(mCurl, CURLOPT_HEADER, 0L) != CURLE_OK) { qDebug() << "Failed to set header"; return false; } if (curl_easy_setopt(mCurl, CURLOPT_NOBODY, 0L) != CURLE_OK) { qDebug() << "Failed to set no body"; return false; } if (curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, write_data) != CURLE_OK) { qDebug() << "Failed to set write function"; return false; } if (curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, &outputFile) != CURLE_OK) { qDebug() << "Failed to set write function"; return false; } if (curl_easy_perform (mCurl) != CURLE_OK) { qDebug() << "Failed to perform download."; return false; } if (!outputFile.commit()) { qDebug() << "Failed to commit data to filesystem."; return false; } return true; } QDateTime SSLConnectionCurl::getLastModifiedHeader(const QString &resource) { QUrl urlCopy = mUrl; urlCopy.setPath(resource); if (curl_easy_setopt(mCurl, CURLOPT_URL, urlCopy.toEncoded().constData()) != CURLE_OK) { qDebug() << "Failed to set URL"; return QDateTime(); } if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 0L) != CURLE_OK) { qDebug() << "Failed to set connect"; return QDateTime(); } if (curl_easy_setopt(mCurl, CURLOPT_HEADER, 1L) != CURLE_OK) { qDebug() << "Failed to set header"; return QDateTime(); } if (curl_easy_setopt(mCurl, CURLOPT_NOBODY, 1L) != CURLE_OK) { qDebug() << "Failed to set no body"; return QDateTime(); } if (curl_easy_setopt(mCurl, CURLOPT_FILETIME, 1L) != CURLE_OK) { qDebug() << "Failed to set filetime"; return QDateTime(); } if (curl_easy_perform (mCurl) != CURLE_OK) { qDebug() << "Failed to perform last modified check."; return QDateTime(); } long filetime = 0; if (curl_easy_getinfo (mCurl, CURLINFO_FILETIME, &filetime) != CURLE_OK) { qDebug() << "Failed to get filetime"; return QDateTime(); } if (filetime == -1) { qDebug() << "Invalid Time"; return QDateTime(); } return QDateTime::fromTime_t(filetime); } void SSLConnectionCurl::setProxy(const QUrl& proxyUrl) { if (curl_easy_setopt(mCurl, CURLOPT_PROXY, proxyUrl.toEncoded().constData()) != CURLE_OK) { qDebug() << "Failed to set proxy"; return; } } void SSLConnectionCurl::setCiphersuites(int ciphers[]) { QStringList cipher_list; for (int i = 0; ciphers[i] != 0; i++) { cipher_list << ssl_get_ciphersuite_name(ciphers[i]); } if (curl_easy_setopt(mCurl, CURLOPT_SSL_CIPHER_LIST, cipher_list.join(":").toLatin1().constData()) != CURLE_OK) { qDebug() << "Failed to set cipher list"; return; } }