comparison ui/downloader.cpp @ 27:62cd56cea09b

Start on polarssl Downloader. This breaks the windows build for now
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 12 Mar 2014 16:15:52 +0100
parents f4f957c58e0a
children d8e93fa1fc93
comparison
equal deleted inserted replaced
26:cbd57d767dfa 27:62cd56cea09b
1 #include "downloader.h" 1 #include "downloader.h"
2 2
3 #ifndef DOWNLOAD_SERVER 3 #ifndef DOWNLOAD_SERVER
4 #define DOWNLOAD_SERVER "https://www.intevation.de" 4 #define DOWNLOAD_SERVER "https://www.intevation.de"
5 #endif
6
7 #ifdef Q_OS_WIN
8 #endif 5 #endif
9 6
10 #include <QFile> 7 #include <QFile>
11 #include <QDir> 8 #include <QDir>
12 #include <QDebug> 9 #include <QDebug>
13 #include <QStandardPaths> 10 #include <QStandardPaths>
11 #include <QUuid>
12 #include <QApplication>
13
14 #include <polarssl/net.h>
15 #include <polarssl/ssl.h>
16 #include <polarssl/entropy.h>
17 #include <polarssl/ctr_drbg.h>
18 #include <polarssl/error.h>
19 #include <polarssl/certs.h>
20
21 #define MAX_SW_SIZE 10485760
22 #define MAX_LIST_SIZE 1048576
23
24 QString getErrorMsg(int ret)
25 {
26 char errbuf[255];
27 polarssl_strerror(ret, errbuf, 255);
28 errbuf[254] = '\0'; /* Just to be sure */
29 return QString::fromLatin1(errbuf);
30 }
14 31
15 Downloader::Downloader(QObject* parent, const QString& url, 32 Downloader::Downloader(QObject* parent, const QString& url,
16 const QByteArray& certificate, 33 const QByteArray& certificate,
17 const QDateTime& newestSW, 34 const QDateTime& newestSW,
18 const QDateTime& newestList): 35 const QDateTime& newestList):
19 QThread(parent), 36 QThread(parent),
20 mUrl(url), 37 mUrl(url),
38 mPinnedCert(certificate),
21 mLastModSW(newestSW), 39 mLastModSW(newestSW),
22 mLastModList(newestList) 40 mLastModList(newestList),
23 { 41 mErrorState(NoError),
42 mInitialized(false),
43 mServerFD(-1)
44 {
45 int ret = -1;
46
47 memset(&mSSL, 0, sizeof(ssl_context));
48
24 if (certificate.isEmpty()) { 49 if (certificate.isEmpty()) {
25 QFile certResource(":certs/kolab.org"); 50 QFile certResource(":certs/kolab.org");
26 certResource.open(QFile::ReadOnly); 51 certResource.open(QFile::ReadOnly);
27 mCert = certResource.readAll(); 52 mPinnedCert = certResource.readAll();
28 certResource.close(); 53 certResource.close();
54 }
55
56 ret = init();
57 if (ret == 0) {
58 mInitialized = true;
59 } else {
60 qDebug() << "Initialization error: " + getErrorMsg(ret);
61 }
62 }
63
64 int Downloader::init()
65 {
66 int ret = -1;
67 QUuid uuid = QUuid::createUuid();
68 QString personalString = QApplication::applicationName() + uuid.toString();
69 QByteArray personalBa = personalString.toLocal8Bit();
70
71 x509_crt_init(&mX509PinnedCert);
72 entropy_init(&mEntropy);
73
74 ret = ssl_init(&mSSL);
75 if (ret != 0) {
76 /* The only documented error is malloc failed */
77 mErrorState = ErrUnknown;
78 return ret;
79 }
80
81 /*
82 * Initialize random generator.
83 * Personalisation string, does not need to be random but
84 * should be unique according to documentation.
85 *
86 * the ctr_drbg structure does not need to be freed explicitly.
87 */
88 ret = ctr_drbg_init(&mCtr_drbg, entropy_func, &mEntropy,
89 (const unsigned char*) personalBa.constData(),
90 personalBa.size());
91 if (ret != 0) {
92 ssl_free(&mSSL);
93 mErrorState = ErrUnknown;
94 return ret;
95 }
96
97 ret = x509_crt_parse(&mX509PinnedCert,
98 (const unsigned char*) mPinnedCert.constData(),
99 mPinnedCert.size());
100 if (ret != 0){
101 ssl_free(&mSSL);
102 mErrorState = InvalidPinnedCertificate;
103 return ret;
104 }
105
106 ssl_set_endpoint(&mSSL, SSL_IS_CLIENT);
107 ssl_set_authmode(&mSSL, SSL_VERIFY_OPTIONAL);
108 ssl_set_ca_chain(&mSSL, &mX509PinnedCert, NULL, NULL);
109 ssl_set_renegotiation(&mSSL, SSL_RENEGOTIATION_DISABLED);
110 ssl_set_rng(&mSSL, ctr_drbg_random, &mCtr_drbg);
111
112 return 0;
113 }
114
115 Downloader::~Downloader() {
116 x509_crt_free(&mX509PinnedCert);
117 entropy_free(&mEntropy);
118 if (mInitialized) {
119 ssl_free(&mSSL);
29 } 120 }
30 } 121 }
31 122
32 QString Downloader::getDataDirectory() 123 QString Downloader::getDataDirectory()
33 { 124 {
47 return QString(); 138 return QString();
48 } 139 }
49 } 140 }
50 return cDir.absolutePath(); 141 return cDir.absolutePath();
51 } 142 }
143
144 int Downloader::establishSSLConnection() {
145 int ret = -1;
146 const x509_crt *peerCert;
147
148 mErrorState = ErrUnknown;
149
150 if (mServerFD == -1) {
151 return -1;
152 }
153
154 ssl_set_bio(&mSSL, net_recv, &mServerFD,
155 net_send, &mServerFD);
156
157 while ((ret = ssl_handshake(&mSSL)) != 0) {
158 if (ret != POLARSSL_ERR_NET_WANT_READ &&
159 ret != POLARSSL_ERR_NET_WANT_WRITE) {
160 qDebug() << "SSL Handshake failed: "
161 << getErrorMsg(ret);
162 return ret;
163 }
164 }
165
166 ret = ssl_get_verify_result(&mSSL);
167
168 if (ret != 0 ) {
169
170 if( ( ret & BADCERT_EXPIRED ) != 0 )
171 qDebug() << "server certificate has expired";
172
173 if( ( ret & BADCERT_REVOKED ) != 0 )
174 qDebug() << "server certificate has been revoked";
175
176 if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
177 qDebug() << "CN mismatch";
178
179 if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
180 qDebug() << "self-signed or not signed by a trusted CA";
181
182 #ifdef RELEASE_BUILD
183 return -1;
184 #endif
185 }
186
187 peerCert = ssl_get_peer_cert(&mSSL);
188
189 if (!peerCert) {
190 mErrorState = InvalidCertificate;
191 qDebug() << "Failed to get peer cert";
192 return -1;
193 }
194
195 if (peerCert->raw.len == 0 ||
196 peerCert->raw.len != mX509PinnedCert.raw.len) {
197 mErrorState = InvalidCertificate;
198 qDebug() << "Certificate length mismatch";
199 return -1;
200 }
201
202 /* You can never be sure what those c++ operators do..
203 if (mPinnedCert != QByteArray::fromRawData(
204 (const char*) peerCert->raw.p,
205 peerCert->raw.len)) {
206 qDebug() << "Certificate content mismatch";
207 }
208 */
209
210 for (unsigned int i = 0; i < peerCert->raw.len; i++) {
211 if (peerCert->raw.p[i] != mX509PinnedCert.raw.p[i]) {
212 qDebug() << "Certificate content mismatch";
213 mErrorState = InvalidCertificate;
214 return -1;
215 }
216 }
217 mErrorState = NoError;
218 return 0;
219 }
220
221
222 void Downloader::run() {
223 int ret;
224
225 if (!mInitialized) {
226 emit error(tr("Failed to initialize SSL Module."), ErrUnknown);
227 return;
228 }
229
230 ret = net_connect(&mServerFD, mUrl.host().toLatin1().constData(),
231 mUrl.port(443));
232 if (ret != 0) {
233 mErrorState = NoConnection;
234 emit error(tr("Failed to connect to %1.").arg(mUrl.host()),
235 mErrorState);
236 return;
237 }
238
239 emit progress(tr("Connected"), 1, -1);
240
241 ret = establishSSLConnection();
242 if (ret != 0) {
243 qDebug() << "SSL conncetion failed: " << getErrorMsg(ret);
244 emit error(tr("Failed to connect to %1.").arg(mUrl.host()),
245 mErrorState);
246 return;
247 }
248
249 qDebug() << "Connected to: " << mUrl.host();
250 // TODO
251
252 emit progress(tr("Closing"), 1, -1);
253 ssl_close_notify (&mSSL);
254
255 if (mServerFD != -1) {
256 net_close(mServerFD);
257 mServerFD = -1;
258 }
259 }

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