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