Mercurial > trustbridge
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 } |