andre@908: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik andre@908: * Software engineering by Intevation GmbH andre@908: * andre@908: * This file is Free Software under the GNU GPL (v>=2) andre@908: * and comes with ABSOLUTELY NO WARRANTY! andre@908: * See LICENSE.txt for details. andre@908: */ andre@908: andre@908: #include "sslconnection_curl.h" andre@908: andre@908: #define CONNECTION_DEBUG andre@908: andre@908: SSLConnectionCurl::SSLConnectionCurl(const QString& url, andre@908: const QByteArray& certificate): andre@908: SSLConnection (url, certificate), andre@908: mCurl (NULL) andre@908: { andre@908: curl_global_init(CURL_GLOBAL_DEFAULT); andre@908: mCurl = curl_easy_init(); andre@908: andre@908: if (!mCurl) { andre@908: qDebug() << "Failed to initialize curl"; andre@908: return; andre@908: } andre@908: andre@908: if (curl_easy_setopt(mCurl, CURLOPT_URL, QUrl(url).toEncoded().constData()) != CURLE_OK) { andre@908: qDebug() << "Setting url failed"; andre@908: return; andre@908: } andre@908: andre@908: if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 1L) != CURLE_OK) { andre@908: /* Should be default anyway */ andre@908: qDebug() << "Setting verifypeer failed"; andre@908: return; andre@908: } andre@908: andre@908: if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYHOST, 0L) != CURLE_OK) { andre@908: /* There are no limitiations for the pinned certificate */ andre@908: qDebug() << "Setting verifyhost failed"; andre@908: return; andre@908: } andre@908: andre@908: mCertFile.open(); andre@908: if (mCertFile.write(mPinnedCert) != mPinnedCert.size()) { andre@908: qDebug() << "Failed to write temporary certificate"; andre@908: return; andre@908: } andre@908: mCertFile.close(); andre@908: andre@908: if (curl_easy_setopt(mCurl, CURLOPT_CAINFO, andre@908: mCertFile.fileName().toUtf8().constData()) != CURLE_OK) { andre@908: qDebug() << "Failed to write temporary certificate"; andre@908: return; andre@908: } andre@908: mInitialized = true; andre@908: andre@908: #ifdef CONNECTION_DEBUG andre@908: curl_easy_setopt(mCurl, CURLOPT_VERBOSE, 1L); andre@908: #endif andre@908: } andre@908: andre@908: SSLConnectionCurl::~SSLConnectionCurl() { andre@908: if (mCurl) { andre@908: curl_easy_cleanup (mCurl); andre@908: } andre@908: if (mInitialized) { andre@908: mCertFile.close(); andre@908: } andre@908: curl_global_cleanup(); andre@908: } andre@908: andre@908: int SSLConnectionCurl::connect() { andre@908: if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 1L) != CURLE_OK) { andre@908: qDebug() << "Failed to set connect only option"; andre@908: return -1; andre@908: } andre@908: if (curl_easy_perform (mCurl) != CURLE_OK) { andre@908: qDebug() << "Failed to connect"; andre@908: mErrorState = NoConnection; andre@908: return -1; andre@908: } andre@908: mConnected = true; andre@908: return 0; andre@908: } andre@908: andre@908: int SSLConnectionCurl::write(const QByteArray& request) { andre@908: size_t written = 0; andre@908: andre@908: if (curl_easy_send (mCurl, request.constData(), request.size(), &written) != CURLE_OK) { andre@908: qDebug() << "Failed to send request"; andre@908: return -1; andre@908: } andre@908: if (written != (size_t)request.size()) { andre@908: qDebug() << "Failed to write everything"; andre@908: return -1; andre@908: } andre@908: return 0; andre@908: } andre@908: andre@908: QByteArray SSLConnectionCurl::read(size_t len) andre@908: { andre@908: unsigned char buf[len]; andre@908: QByteArray retval(""); andre@908: CURLcode ret; andre@908: size_t read = 0; andre@908: unsigned int tries = 0; andre@908: andre@908: do { andre@908: memset (buf, 0, sizeof(buf)); andre@908: ret = curl_easy_recv (mCurl, buf, len, &read); andre@908: if (ret == CURLE_OK && read == 0) { andre@908: return retval; andre@908: } andre@908: if (ret == CURLE_AGAIN) { andre@908: tries++; andre@908: continue; andre@908: } andre@908: if (ret != CURLE_OK) { andre@908: qDebug() << "Read failed."; andre@908: return QByteArray(); andre@908: } andre@908: if (len < (len - read)) { andre@908: /* Should never happen if ssl_read behaves */ andre@908: qDebug() << "integer overflow in polarSSLRead"; andre@908: return QByteArray(); andre@908: } andre@908: andre@908: len -= read; andre@908: retval.append((const char *)buf, read); andre@908: } while (len > 0 && tries < 10); andre@908: andre@908: return retval; andre@908: }