view ui/sslconnection_curl.cpp @ 908:d1c951b3012d

Curl based implementation of sslconnection
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 13 Aug 2014 19:35:08 +0200
parents
children eaed02defe6a
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"

#define 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;
    }

    if (curl_easy_setopt(mCurl, CURLOPT_URL, QUrl(url).toEncoded().constData()) != CURLE_OK) {
        qDebug() << "Setting url failed";
        return;
    }

    if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 1L) != CURLE_OK) {
        /* Should be default anyway */
        qDebug() << "Setting verifypeer failed";
        return;
    }

    if (curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYHOST, 0L) != CURLE_OK) {
        /* There are no limitiations for the pinned certificate */
        qDebug() << "Setting verifyhost failed";
        return;
    }

    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 write temporary 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() {
    if (curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 1L) != CURLE_OK) {
        qDebug() << "Failed to set connect only option";
        return -1;
    }
    if (curl_easy_perform (mCurl) != CURLE_OK) {
        qDebug() << "Failed to connect";
        mErrorState = NoConnection;
        return -1;
    }
    mConnected = true;
    return 0;
}

int SSLConnectionCurl::write(const QByteArray& request) {
    size_t written = 0;

    if (curl_easy_send (mCurl, request.constData(), request.size(), &written) != CURLE_OK) {
        qDebug() << "Failed to send request";
        return -1;
    }
    if (written != (size_t)request.size()) {
        qDebug() << "Failed to write everything";
        return -1;
    }
    return 0;
}

QByteArray SSLConnectionCurl::read(size_t len)
{
    unsigned char buf[len];
    QByteArray retval("");
    CURLcode ret;
    size_t read = 0;
    unsigned int tries = 0;

    do {
        memset (buf, 0, sizeof(buf));
        ret = curl_easy_recv (mCurl, buf, len, &read);
        if (ret == CURLE_OK && read == 0) {
            return retval;
        }
        if (ret == CURLE_AGAIN) {
            tries++;
            continue;
        }
        if (ret != CURLE_OK) {
            qDebug() << "Read failed.";
            return QByteArray();
        }
        if (len < (len - read)) {
            /* Should never happen if ssl_read behaves */
            qDebug() << "integer overflow in polarSSLRead";
            return QByteArray();
        }

        len -= read;
        retval.append((const char *)buf, read);
    } while (len > 0 && tries < 10);

    return retval;
}

http://wald.intevation.org/projects/trustbridge/