Tests: Fix compilation on Windows.
[profile/ivi/qtbase.git] / tests / auto / network / ssl / qsslkey / tst_qsslkey.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44 #include <qsslkey.h>
45 #include <qsslsocket.h>
46
47 #include <QtNetwork/qhostaddress.h>
48 #include <QtNetwork/qnetworkproxy.h>
49
50 class tst_QSslKey : public QObject
51 {
52     Q_OBJECT
53
54     struct KeyInfo {
55         QFileInfo fileInfo;
56         QSsl::KeyAlgorithm algorithm;
57         QSsl::KeyType type;
58         int length;
59         QSsl::EncodingFormat format;
60         KeyInfo(
61             const QFileInfo &fileInfo, QSsl::KeyAlgorithm algorithm, QSsl::KeyType type,
62             int length, QSsl::EncodingFormat format)
63             : fileInfo(fileInfo), algorithm(algorithm), type(type), length(length)
64             , format(format) {}
65     };
66
67     QList<KeyInfo> keyInfoList;
68
69     void createPlainTestRows();
70
71 public:
72     tst_QSslKey();
73     virtual ~tst_QSslKey();
74
75 public slots:
76     void initTestCase_data();
77     void init();
78     void cleanup();
79
80 #ifndef QT_NO_OPENSSL
81
82 private slots:
83     void emptyConstructor();
84     void constructor_data();
85     void constructor();
86     void copyAndAssign_data();
87     void copyAndAssign();
88     void equalsOperator();
89     void length_data();
90     void length();
91     void toPemOrDer_data();
92     void toPemOrDer();
93     void toEncryptedPemOrDer_data();
94     void toEncryptedPemOrDer();
95
96     void passphraseChecks();
97 #endif
98 };
99
100 tst_QSslKey::tst_QSslKey()
101 {
102 #ifdef Q_OS_MAC
103     // applicationDirPath() points to a path inside the app bundle on Mac.
104     QDir dir(qApp->applicationDirPath() + QLatin1String("/../../../keys"));
105 #else
106     QDir dir(SRCDIR + QLatin1String("/keys"));  // prefer this way to avoid ifdeffery and support shadow builds?
107 #endif
108     QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable);
109     QRegExp rx(QLatin1String("^(rsa|dsa)-(pub|pri)-(\\d+)\\.(pem|der)$"));
110     foreach (QFileInfo fileInfo, fileInfoList) {
111         if (rx.indexIn(fileInfo.fileName()) >= 0)
112             keyInfoList << KeyInfo(
113                 fileInfo,
114                 rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa : QSsl::Dsa,
115                 rx.cap(2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
116                 rx.cap(3).toInt(),
117                 rx.cap(4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
118     }
119 }
120
121 tst_QSslKey::~tst_QSslKey()
122 {
123 }
124
125 void tst_QSslKey::initTestCase_data()
126 {
127 }
128
129 void tst_QSslKey::init()
130 {
131 }
132
133 void tst_QSslKey::cleanup()
134 {
135 }
136
137 static QByteArray readFile(const QString &absFilePath)
138 {
139     QFile file(absFilePath);
140     if (!file.open(QIODevice::ReadOnly)) {
141         QWARN("failed to open file");
142         return QByteArray();
143     }
144     return file.readAll();
145 }
146
147 #ifndef QT_NO_OPENSSL
148
149 void tst_QSslKey::emptyConstructor()
150 {
151     if (!QSslSocket::supportsSsl())
152         return;
153
154     QSslKey key;
155     QVERIFY(key.isNull());
156     QVERIFY(key.length() < 0);
157
158     QSslKey key2;
159     QCOMPARE(key, key2);
160 }
161
162 Q_DECLARE_METATYPE(QSsl::KeyAlgorithm)
163 Q_DECLARE_METATYPE(QSsl::KeyType)
164 Q_DECLARE_METATYPE(QSsl::EncodingFormat)
165
166 void tst_QSslKey::createPlainTestRows()
167 {
168     QTest::addColumn<QString>("absFilePath");
169     QTest::addColumn<QSsl::KeyAlgorithm>("algorithm");
170     QTest::addColumn<QSsl::KeyType>("type");
171     QTest::addColumn<int>("length");
172     QTest::addColumn<QSsl::EncodingFormat>("format");
173     foreach (KeyInfo keyInfo, keyInfoList) {
174         QTest::newRow(keyInfo.fileInfo.fileName().toLatin1())
175             << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
176             << keyInfo.length << keyInfo.format;
177     }
178 }
179
180 void tst_QSslKey::constructor_data()
181 {
182     createPlainTestRows();
183 }
184
185 void tst_QSslKey::constructor()
186 {
187     if (!QSslSocket::supportsSsl())
188         return;
189
190     QFETCH(QString, absFilePath);
191     QFETCH(QSsl::KeyAlgorithm, algorithm);
192     QFETCH(QSsl::KeyType, type);
193     QFETCH(QSsl::EncodingFormat, format);
194
195     QByteArray encoded = readFile(absFilePath);
196     QSslKey key(encoded, algorithm, format, type);
197     QVERIFY(!key.isNull());
198 }
199
200 void tst_QSslKey::copyAndAssign_data()
201 {
202     createPlainTestRows();
203 }
204
205 void tst_QSslKey::copyAndAssign()
206 {
207     if (!QSslSocket::supportsSsl())
208         return;
209
210     QFETCH(QString, absFilePath);
211     QFETCH(QSsl::KeyAlgorithm, algorithm);
212     QFETCH(QSsl::KeyType, type);
213     QFETCH(QSsl::EncodingFormat, format);
214
215     QByteArray encoded = readFile(absFilePath);
216     QSslKey key(encoded, algorithm, format, type);
217
218     QSslKey copied(key);
219     QCOMPARE(key, copied);
220     QCOMPARE(key.algorithm(), copied.algorithm());
221     QCOMPARE(key.type(), copied.type());
222     QCOMPARE(key.length(), copied.length());
223     QCOMPARE(key.toPem(), copied.toPem());
224     QCOMPARE(key.toDer(), copied.toDer());
225
226     QSslKey assigned = key;
227     QCOMPARE(key, assigned);
228     QCOMPARE(key.algorithm(), assigned.algorithm());
229     QCOMPARE(key.type(), assigned.type());
230     QCOMPARE(key.length(), assigned.length());
231     QCOMPARE(key.toPem(), assigned.toPem());
232     QCOMPARE(key.toDer(), assigned.toDer());
233 }
234
235 void tst_QSslKey::equalsOperator()
236 {
237     // ### unimplemented
238 }
239
240 void tst_QSslKey::length_data()
241 {
242     createPlainTestRows();
243 }
244
245 void tst_QSslKey::length()
246 {
247     if (!QSslSocket::supportsSsl())
248         return;
249
250     QFETCH(QString, absFilePath);
251     QFETCH(QSsl::KeyAlgorithm, algorithm);
252     QFETCH(QSsl::KeyType, type);
253     QFETCH(int, length);
254     QFETCH(QSsl::EncodingFormat, format);
255
256     QByteArray encoded = readFile(absFilePath);
257     QSslKey key(encoded, algorithm, format, type);
258     QVERIFY(!key.isNull());
259     QCOMPARE(key.length(), length);
260 }
261
262 void tst_QSslKey::toPemOrDer_data()
263 {
264     createPlainTestRows();
265 }
266
267 void tst_QSslKey::toPemOrDer()
268 {
269     if (!QSslSocket::supportsSsl())
270         return;
271
272     QFETCH(QString, absFilePath);
273     QFETCH(QSsl::KeyAlgorithm, algorithm);
274     QFETCH(QSsl::KeyType, type);
275     QFETCH(QSsl::EncodingFormat, format);
276
277     QByteArray encoded = readFile(absFilePath);
278     QSslKey key(encoded, algorithm, format, type);
279     QVERIFY(!key.isNull());
280     if (format == QSsl::Pem)
281         encoded.replace('\r', "");
282     QCOMPARE(format == QSsl::Pem ? key.toPem() : key.toDer(), encoded);
283 }
284
285 void tst_QSslKey::toEncryptedPemOrDer_data()
286 {
287     QTest::addColumn<QString>("absFilePath");
288     QTest::addColumn<QSsl::KeyAlgorithm>("algorithm");
289     QTest::addColumn<QSsl::KeyType>("type");
290     QTest::addColumn<QSsl::EncodingFormat>("format");
291     QTest::addColumn<QString>("password");
292
293     QStringList passwords;
294     passwords << " " << "foobar" << "foo bar"
295               << "aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?"; // ### add more (?)
296     foreach (KeyInfo keyInfo, keyInfoList) {
297         foreach (QString password, passwords) {
298             QString testName = QString("%1-%2-%3-%4").arg(keyInfo.fileInfo.fileName())
299                 .arg(keyInfo.algorithm == QSsl::Rsa ? "RSA" : "DSA")
300                 .arg(keyInfo.type == QSsl::PrivateKey ? "PrivateKey" : "PublicKey")
301                 .arg(keyInfo.format == QSsl::Pem ? "PEM" : "DER");
302             QTest::newRow(testName.toLatin1())
303                 << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
304                 << keyInfo.format << password;
305         }
306     }
307 }
308
309 void tst_QSslKey::toEncryptedPemOrDer()
310 {
311     if (!QSslSocket::supportsSsl())
312         return;
313
314     QFETCH(QString, absFilePath);
315     QFETCH(QSsl::KeyAlgorithm, algorithm);
316     QFETCH(QSsl::KeyType, type);
317     QFETCH(QSsl::EncodingFormat, format);
318     QFETCH(QString, password);
319
320     QByteArray plain = readFile(absFilePath);
321     QSslKey key(plain, algorithm, format, type);
322     QVERIFY(!key.isNull());
323
324     QByteArray pwBytes(password.toLatin1());
325
326     if (type == QSsl::PrivateKey) {
327         QByteArray encryptedPem = key.toPem(pwBytes);
328         QVERIFY(!encryptedPem.isEmpty());
329         QSslKey keyPem(encryptedPem, algorithm, QSsl::Pem, type, pwBytes);
330         QVERIFY(!keyPem.isNull());
331         QCOMPARE(keyPem, key);
332         QCOMPARE(keyPem.toPem(), key.toPem());
333     } else {
334         // verify that public keys are never encrypted by toPem()
335         QByteArray encryptedPem = key.toPem(pwBytes);
336         QVERIFY(!encryptedPem.isEmpty());
337         QByteArray plainPem = key.toPem();
338         QVERIFY(!plainPem.isEmpty());
339         QCOMPARE(encryptedPem, plainPem);
340     }
341
342     if (type == QSsl::PrivateKey) {
343         QByteArray encryptedDer = key.toDer(pwBytes);
344         // ### at this point, encryptedDer is invalid, hence the below QEXPECT_FAILs
345         QVERIFY(!encryptedDer.isEmpty());
346         QSslKey keyDer(encryptedDer, algorithm, QSsl::Der, type, pwBytes);
347         if (type == QSsl::PrivateKey)
348             QEXPECT_FAIL(
349                 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
350         QVERIFY(!keyDer.isNull());
351         if (type == QSsl::PrivateKey)
352             QEXPECT_FAIL(
353                 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
354         QCOMPARE(keyDer.toPem(), key.toPem());
355     } else {
356         // verify that public keys are never encrypted by toDer()
357         QByteArray encryptedDer = key.toDer(pwBytes);
358         QVERIFY(!encryptedDer.isEmpty());
359         QByteArray plainDer = key.toDer();
360         QVERIFY(!plainDer.isEmpty());
361         QCOMPARE(encryptedDer, plainDer);
362     }
363
364     // ### add a test to verify that public keys are _decrypted_ correctly (by the ctor)
365 }
366
367 void tst_QSslKey::passphraseChecks()
368 {
369     {
370         QString fileName(SRCDIR "/rsa-with-passphrase.pem");
371         QFile keyFile(fileName);
372         QVERIFY(keyFile.exists());
373         {
374             if (!keyFile.isOpen())
375                 keyFile.open(QIODevice::ReadOnly);
376             else
377                 keyFile.reset();
378             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
379             QVERIFY(key.isNull()); // null passphrase => should not be able to decode key
380         }
381         {
382             if (!keyFile.isOpen())
383                 keyFile.open(QIODevice::ReadOnly);
384             else
385                 keyFile.reset();
386             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
387             QVERIFY(key.isNull()); // empty passphrase => should not be able to decode key
388         }
389         {
390             if (!keyFile.isOpen())
391                 keyFile.open(QIODevice::ReadOnly);
392             else
393                 keyFile.reset();
394             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!");
395             QVERIFY(key.isNull()); // wrong passphrase => should not be able to decode key
396         }
397         {
398             if (!keyFile.isOpen())
399                 keyFile.open(QIODevice::ReadOnly);
400             else
401                 keyFile.reset();
402             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123");
403             QVERIFY(!key.isNull()); // correct passphrase
404         }
405     }
406
407     {
408         // be sure and check a key without passphrase too
409         QString fileName(SRCDIR "/rsa-without-passphrase.pem");
410         QFile keyFile(fileName);
411         {
412             if (!keyFile.isOpen())
413                 keyFile.open(QIODevice::ReadOnly);
414             else
415                 keyFile.reset();
416             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
417             QVERIFY(!key.isNull()); // null passphrase => should be able to decode key
418         }
419         {
420             if (!keyFile.isOpen())
421                 keyFile.open(QIODevice::ReadOnly);
422             else
423                 keyFile.reset();
424             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
425             QVERIFY(!key.isNull()); // empty passphrase => should be able to decode key
426         }
427         {
428             if (!keyFile.isOpen())
429                 keyFile.open(QIODevice::ReadOnly);
430             else
431                 keyFile.reset();
432             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "xxx");
433             QVERIFY(!key.isNull()); // passphrase given but key is not encrypted anyway => should work
434         }
435     }
436 }
437
438 #endif
439
440 QTEST_MAIN(tst_QSslKey)
441 #include "tst_qsslkey.moc"