Merge branch 'master' into refactor
[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 #ifdef Q_OS_SYMBIAN
51 // In Symbian OS test data is located in applications private dir
52 // Current path (C:\private\<UID>) contains only ascii chars
53 #define SRCDIR "."
54 #endif
55
56 class tst_QSslKey : public QObject
57 {
58     Q_OBJECT
59
60     struct KeyInfo {
61         QFileInfo fileInfo;
62         QSsl::KeyAlgorithm algorithm;
63         QSsl::KeyType type;
64         int length;
65         QSsl::EncodingFormat format;
66         KeyInfo(
67             const QFileInfo &fileInfo, QSsl::KeyAlgorithm algorithm, QSsl::KeyType type,
68             int length, QSsl::EncodingFormat format)
69             : fileInfo(fileInfo), algorithm(algorithm), type(type), length(length)
70             , format(format) {}
71     };
72
73     QList<KeyInfo> keyInfoList;
74
75     void createPlainTestRows();
76
77 public:
78     tst_QSslKey();
79     virtual ~tst_QSslKey();
80
81 public slots:
82     void initTestCase_data();
83     void init();
84     void cleanup();
85
86 #ifndef QT_NO_OPENSSL
87
88 private slots:
89     void emptyConstructor();
90     void constructor_data();
91     void constructor();
92     void copyAndAssign_data();
93     void copyAndAssign();
94     void equalsOperator();
95     void length_data();
96     void length();
97     void toPemOrDer_data();
98     void toPemOrDer();
99     void toEncryptedPemOrDer_data();
100     void toEncryptedPemOrDer();
101
102     void passphraseChecks();
103 #endif
104 };
105
106 tst_QSslKey::tst_QSslKey()
107 {
108 #ifdef Q_WS_MAC
109     // applicationDirPath() points to a path inside the app bundle on Mac.
110     QDir dir(qApp->applicationDirPath() + QLatin1String("/../../../keys"));
111 #else
112     QDir dir(SRCDIR + QLatin1String("/keys"));  // prefer this way to avoid ifdeffery and support shadow builds?
113 #endif
114     QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable);
115     QRegExp rx(QLatin1String("^(rsa|dsa)-(pub|pri)-(\\d+)\\.(pem|der)$"));
116     foreach (QFileInfo fileInfo, fileInfoList) {
117         if (rx.indexIn(fileInfo.fileName()) >= 0)
118             keyInfoList << KeyInfo(
119                 fileInfo,
120                 rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa : QSsl::Dsa,
121                 rx.cap(2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
122                 rx.cap(3).toInt(),
123                 rx.cap(4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
124     }
125 }
126
127 tst_QSslKey::~tst_QSslKey()
128 {
129 }
130
131 void tst_QSslKey::initTestCase_data()
132 {
133 }
134
135 void tst_QSslKey::init()
136 {
137 }
138
139 void tst_QSslKey::cleanup()
140 {
141 }
142
143 static QByteArray readFile(const QString &absFilePath)
144 {
145     QFile file(absFilePath);
146     if (!file.open(QIODevice::ReadOnly)) {
147         QWARN("failed to open file");
148         return QByteArray();
149     }
150     return file.readAll();
151 }
152
153 #ifndef QT_NO_OPENSSL
154
155 void tst_QSslKey::emptyConstructor()
156 {
157     if (!QSslSocket::supportsSsl())
158         return;
159
160     QSslKey key;
161     QVERIFY(key.isNull());
162     QVERIFY(key.length() < 0);
163
164     QSslKey key2;
165     QCOMPARE(key, key2);
166 }
167
168 Q_DECLARE_METATYPE(QSsl::KeyAlgorithm)
169 Q_DECLARE_METATYPE(QSsl::KeyType)
170 Q_DECLARE_METATYPE(QSsl::EncodingFormat)
171
172 void tst_QSslKey::createPlainTestRows()
173 {
174     QTest::addColumn<QString>("absFilePath");
175     QTest::addColumn<QSsl::KeyAlgorithm>("algorithm");
176     QTest::addColumn<QSsl::KeyType>("type");
177     QTest::addColumn<int>("length");
178     QTest::addColumn<QSsl::EncodingFormat>("format");
179     foreach (KeyInfo keyInfo, keyInfoList) {
180         QTest::newRow(keyInfo.fileInfo.fileName().toLatin1())
181             << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
182             << keyInfo.length << keyInfo.format;
183     }
184 }
185
186 void tst_QSslKey::constructor_data()
187 {
188     createPlainTestRows();
189 }
190
191 void tst_QSslKey::constructor()
192 {
193     if (!QSslSocket::supportsSsl())
194         return;
195
196     QFETCH(QString, absFilePath);
197     QFETCH(QSsl::KeyAlgorithm, algorithm);
198     QFETCH(QSsl::KeyType, type);
199     QFETCH(QSsl::EncodingFormat, format);
200
201     QByteArray encoded = readFile(absFilePath);
202     QSslKey key(encoded, algorithm, format, type);
203     QVERIFY(!key.isNull());
204 }
205
206 void tst_QSslKey::copyAndAssign_data()
207 {
208     createPlainTestRows();
209 }
210
211 void tst_QSslKey::copyAndAssign()
212 {
213     if (!QSslSocket::supportsSsl())
214         return;
215
216     QFETCH(QString, absFilePath);
217     QFETCH(QSsl::KeyAlgorithm, algorithm);
218     QFETCH(QSsl::KeyType, type);
219     QFETCH(QSsl::EncodingFormat, format);
220
221     QByteArray encoded = readFile(absFilePath);
222     QSslKey key(encoded, algorithm, format, type);
223
224     QSslKey copied(key);
225     QCOMPARE(key, copied);
226     QCOMPARE(key.algorithm(), copied.algorithm());
227     QCOMPARE(key.type(), copied.type());
228     QCOMPARE(key.length(), copied.length());
229     QCOMPARE(key.toPem(), copied.toPem());
230     QCOMPARE(key.toDer(), copied.toDer());
231
232     QSslKey assigned = key;
233     QCOMPARE(key, assigned);
234     QCOMPARE(key.algorithm(), assigned.algorithm());
235     QCOMPARE(key.type(), assigned.type());
236     QCOMPARE(key.length(), assigned.length());
237     QCOMPARE(key.toPem(), assigned.toPem());
238     QCOMPARE(key.toDer(), assigned.toDer());
239 }
240
241 void tst_QSslKey::equalsOperator()
242 {
243     // ### unimplemented
244 }
245
246 void tst_QSslKey::length_data()
247 {
248     createPlainTestRows();
249 }
250
251 void tst_QSslKey::length()
252 {
253     if (!QSslSocket::supportsSsl())
254         return;
255
256     QFETCH(QString, absFilePath);
257     QFETCH(QSsl::KeyAlgorithm, algorithm);
258     QFETCH(QSsl::KeyType, type);
259     QFETCH(int, length);
260     QFETCH(QSsl::EncodingFormat, format);
261
262     QByteArray encoded = readFile(absFilePath);
263     QSslKey key(encoded, algorithm, format, type);
264     QVERIFY(!key.isNull());
265     QCOMPARE(key.length(), length);
266 }
267
268 void tst_QSslKey::toPemOrDer_data()
269 {
270     createPlainTestRows();
271 }
272
273 void tst_QSslKey::toPemOrDer()
274 {
275     if (!QSslSocket::supportsSsl())
276         return;
277
278     QFETCH(QString, absFilePath);
279     QFETCH(QSsl::KeyAlgorithm, algorithm);
280     QFETCH(QSsl::KeyType, type);
281     QFETCH(QSsl::EncodingFormat, format);
282
283     QByteArray encoded = readFile(absFilePath);
284     QSslKey key(encoded, algorithm, format, type);
285     QVERIFY(!key.isNull());
286     if (format == QSsl::Pem)
287         encoded.replace('\r', "");
288     QCOMPARE(format == QSsl::Pem ? key.toPem() : key.toDer(), encoded);
289 }
290
291 void tst_QSslKey::toEncryptedPemOrDer_data()
292 {
293     QTest::addColumn<QString>("absFilePath");
294     QTest::addColumn<QSsl::KeyAlgorithm>("algorithm");
295     QTest::addColumn<QSsl::KeyType>("type");
296     QTest::addColumn<QSsl::EncodingFormat>("format");
297     QTest::addColumn<QString>("password");
298
299     QStringList passwords;
300     passwords << " " << "foobar" << "foo bar"
301               << "aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?"; // ### add more (?)
302     foreach (KeyInfo keyInfo, keyInfoList) {
303         foreach (QString password, passwords) {
304             QString testName = QString("%1-%2-%3-%4").arg(keyInfo.fileInfo.fileName())
305                 .arg(keyInfo.algorithm == QSsl::Rsa ? "RSA" : "DSA")
306                 .arg(keyInfo.type == QSsl::PrivateKey ? "PrivateKey" : "PublicKey")
307                 .arg(keyInfo.format == QSsl::Pem ? "PEM" : "DER");
308             QTest::newRow(testName.toLatin1())
309                 << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
310                 << keyInfo.format << password;
311         }
312     }
313 }
314
315 void tst_QSslKey::toEncryptedPemOrDer()
316 {
317     if (!QSslSocket::supportsSsl())
318         return;
319
320     QFETCH(QString, absFilePath);
321     QFETCH(QSsl::KeyAlgorithm, algorithm);
322     QFETCH(QSsl::KeyType, type);
323     QFETCH(QSsl::EncodingFormat, format);
324     QFETCH(QString, password);
325
326     QByteArray plain = readFile(absFilePath);
327     QSslKey key(plain, algorithm, format, type);
328     QVERIFY(!key.isNull());
329
330     QByteArray pwBytes(password.toLatin1());
331
332     if (type == QSsl::PrivateKey) {
333         QByteArray encryptedPem = key.toPem(pwBytes);
334         QVERIFY(!encryptedPem.isEmpty());
335         QSslKey keyPem(encryptedPem, algorithm, QSsl::Pem, type, pwBytes);
336         QVERIFY(!keyPem.isNull());
337         QCOMPARE(keyPem, key);
338         QCOMPARE(keyPem.toPem(), key.toPem());
339     } else {
340         // verify that public keys are never encrypted by toPem()
341         QByteArray encryptedPem = key.toPem(pwBytes);
342         QVERIFY(!encryptedPem.isEmpty());
343         QByteArray plainPem = key.toPem();
344         QVERIFY(!plainPem.isEmpty());
345         QCOMPARE(encryptedPem, plainPem);
346     }
347
348     if (type == QSsl::PrivateKey) {
349         QByteArray encryptedDer = key.toDer(pwBytes);
350         // ### at this point, encryptedDer is invalid, hence the below QEXPECT_FAILs
351         QVERIFY(!encryptedDer.isEmpty());
352         QSslKey keyDer(encryptedDer, algorithm, QSsl::Der, type, pwBytes);
353         if (type == QSsl::PrivateKey)
354             QEXPECT_FAIL(
355                 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
356         QVERIFY(!keyDer.isNull());
357         if (type == QSsl::PrivateKey)
358             QEXPECT_FAIL(
359                 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
360         QCOMPARE(keyDer.toPem(), key.toPem());
361     } else {
362         // verify that public keys are never encrypted by toDer()
363         QByteArray encryptedDer = key.toDer(pwBytes);
364         QVERIFY(!encryptedDer.isEmpty());
365         QByteArray plainDer = key.toDer();
366         QVERIFY(!plainDer.isEmpty());
367         QCOMPARE(encryptedDer, plainDer);
368     }
369
370     // ### add a test to verify that public keys are _decrypted_ correctly (by the ctor)
371 }
372
373 void tst_QSslKey::passphraseChecks()
374 {
375     {
376         QString fileName(SRCDIR "/rsa-with-passphrase.pem");
377         QFile keyFile(fileName);
378         QVERIFY(keyFile.exists());
379         {
380             if (!keyFile.isOpen())
381                 keyFile.open(QIODevice::ReadOnly);
382             else
383                 keyFile.reset();
384             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
385             QVERIFY(key.isNull()); // null passphrase => should not be able to decode key
386         }
387         {
388             if (!keyFile.isOpen())
389                 keyFile.open(QIODevice::ReadOnly);
390             else
391                 keyFile.reset();
392             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
393             QVERIFY(key.isNull()); // empty passphrase => should not be able to decode key
394         }
395         {
396             if (!keyFile.isOpen())
397                 keyFile.open(QIODevice::ReadOnly);
398             else
399                 keyFile.reset();
400             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!");
401             QVERIFY(key.isNull()); // wrong passphrase => should not be able to decode key
402         }
403         {
404             if (!keyFile.isOpen())
405                 keyFile.open(QIODevice::ReadOnly);
406             else
407                 keyFile.reset();
408             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123");
409             QVERIFY(!key.isNull()); // correct passphrase
410         }
411     }
412
413     {
414         // be sure and check a key without passphrase too
415         QString fileName(SRCDIR "/rsa-without-passphrase.pem");
416         QFile keyFile(fileName);
417         {
418             if (!keyFile.isOpen())
419                 keyFile.open(QIODevice::ReadOnly);
420             else
421                 keyFile.reset();
422             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
423             QVERIFY(!key.isNull()); // null passphrase => should be able to decode key
424         }
425         {
426             if (!keyFile.isOpen())
427                 keyFile.open(QIODevice::ReadOnly);
428             else
429                 keyFile.reset();
430             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
431             QVERIFY(!key.isNull()); // empty passphrase => should be able to decode key
432         }
433         {
434             if (!keyFile.isOpen())
435                 keyFile.open(QIODevice::ReadOnly);
436             else
437                 keyFile.reset();
438             QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "xxx");
439             QVERIFY(!key.isNull()); // passphrase given but key is not encrypted anyway => should work
440         }
441     }
442 }
443
444 #endif
445
446 QTEST_MAIN(tst_QSslKey)
447 #include "tst_qsslkey.moc"