1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
45 #include <qsslsocket.h>
47 #include <QtNetwork/qhostaddress.h>
48 #include <QtNetwork/qnetworkproxy.h>
51 // In Symbian OS test data is located in applications private dir
52 // Current path (C:\private\<UID>) contains only ascii chars
56 class tst_QSslKey : public QObject
62 QSsl::KeyAlgorithm algorithm;
65 QSsl::EncodingFormat format;
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)
73 QList<KeyInfo> keyInfoList;
75 void createPlainTestRows();
79 virtual ~tst_QSslKey();
82 void initTestCase_data();
89 void emptyConstructor();
90 void constructor_data();
92 void copyAndAssign_data();
94 void equalsOperator();
97 void toPemOrDer_data();
99 void toEncryptedPemOrDer_data();
100 void toEncryptedPemOrDer();
102 void passphraseChecks();
106 tst_QSslKey::tst_QSslKey()
109 // applicationDirPath() points to a path inside the app bundle on Mac.
110 QDir dir(qApp->applicationDirPath() + QLatin1String("/../../../keys"));
112 QDir dir(SRCDIR + QLatin1String("/keys")); // prefer this way to avoid ifdeffery and support shadow builds?
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(
120 rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa : QSsl::Dsa,
121 rx.cap(2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
123 rx.cap(4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
127 tst_QSslKey::~tst_QSslKey()
131 void tst_QSslKey::initTestCase_data()
135 void tst_QSslKey::init()
139 void tst_QSslKey::cleanup()
143 static QByteArray readFile(const QString &absFilePath)
145 QFile file(absFilePath);
146 if (!file.open(QIODevice::ReadOnly)) {
147 QWARN("failed to open file");
150 return file.readAll();
153 #ifndef QT_NO_OPENSSL
155 void tst_QSslKey::emptyConstructor()
157 if (!QSslSocket::supportsSsl())
161 QVERIFY(key.isNull());
162 QVERIFY(key.length() < 0);
168 Q_DECLARE_METATYPE(QSsl::KeyAlgorithm)
169 Q_DECLARE_METATYPE(QSsl::KeyType)
170 Q_DECLARE_METATYPE(QSsl::EncodingFormat)
172 void tst_QSslKey::createPlainTestRows()
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;
186 void tst_QSslKey::constructor_data()
188 createPlainTestRows();
191 void tst_QSslKey::constructor()
193 if (!QSslSocket::supportsSsl())
196 QFETCH(QString, absFilePath);
197 QFETCH(QSsl::KeyAlgorithm, algorithm);
198 QFETCH(QSsl::KeyType, type);
199 QFETCH(QSsl::EncodingFormat, format);
201 QByteArray encoded = readFile(absFilePath);
202 QSslKey key(encoded, algorithm, format, type);
203 QVERIFY(!key.isNull());
206 void tst_QSslKey::copyAndAssign_data()
208 createPlainTestRows();
211 void tst_QSslKey::copyAndAssign()
213 if (!QSslSocket::supportsSsl())
216 QFETCH(QString, absFilePath);
217 QFETCH(QSsl::KeyAlgorithm, algorithm);
218 QFETCH(QSsl::KeyType, type);
219 QFETCH(QSsl::EncodingFormat, format);
221 QByteArray encoded = readFile(absFilePath);
222 QSslKey key(encoded, algorithm, format, type);
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());
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());
241 void tst_QSslKey::equalsOperator()
246 void tst_QSslKey::length_data()
248 createPlainTestRows();
251 void tst_QSslKey::length()
253 if (!QSslSocket::supportsSsl())
256 QFETCH(QString, absFilePath);
257 QFETCH(QSsl::KeyAlgorithm, algorithm);
258 QFETCH(QSsl::KeyType, type);
260 QFETCH(QSsl::EncodingFormat, format);
262 QByteArray encoded = readFile(absFilePath);
263 QSslKey key(encoded, algorithm, format, type);
264 QVERIFY(!key.isNull());
265 QCOMPARE(key.length(), length);
268 void tst_QSslKey::toPemOrDer_data()
270 createPlainTestRows();
273 void tst_QSslKey::toPemOrDer()
275 if (!QSslSocket::supportsSsl())
278 QFETCH(QString, absFilePath);
279 QFETCH(QSsl::KeyAlgorithm, algorithm);
280 QFETCH(QSsl::KeyType, type);
281 QFETCH(QSsl::EncodingFormat, format);
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);
291 void tst_QSslKey::toEncryptedPemOrDer_data()
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");
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;
315 void tst_QSslKey::toEncryptedPemOrDer()
317 if (!QSslSocket::supportsSsl())
320 QFETCH(QString, absFilePath);
321 QFETCH(QSsl::KeyAlgorithm, algorithm);
322 QFETCH(QSsl::KeyType, type);
323 QFETCH(QSsl::EncodingFormat, format);
324 QFETCH(QString, password);
326 QByteArray plain = readFile(absFilePath);
327 QSslKey key(plain, algorithm, format, type);
328 QVERIFY(!key.isNull());
330 QByteArray pwBytes(password.toLatin1());
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());
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);
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)
355 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
356 QVERIFY(!keyDer.isNull());
357 if (type == QSsl::PrivateKey)
359 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
360 QCOMPARE(keyDer.toPem(), key.toPem());
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);
370 // ### add a test to verify that public keys are _decrypted_ correctly (by the ctor)
373 void tst_QSslKey::passphraseChecks()
376 QString fileName(SRCDIR "/rsa-with-passphrase.pem");
377 QFile keyFile(fileName);
378 QVERIFY(keyFile.exists());
380 if (!keyFile.isOpen())
381 keyFile.open(QIODevice::ReadOnly);
384 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
385 QVERIFY(key.isNull()); // null passphrase => should not be able to decode key
388 if (!keyFile.isOpen())
389 keyFile.open(QIODevice::ReadOnly);
392 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
393 QVERIFY(key.isNull()); // empty passphrase => should not be able to decode key
396 if (!keyFile.isOpen())
397 keyFile.open(QIODevice::ReadOnly);
400 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!");
401 QVERIFY(key.isNull()); // wrong passphrase => should not be able to decode key
404 if (!keyFile.isOpen())
405 keyFile.open(QIODevice::ReadOnly);
408 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123");
409 QVERIFY(!key.isNull()); // correct passphrase
414 // be sure and check a key without passphrase too
415 QString fileName(SRCDIR "/rsa-without-passphrase.pem");
416 QFile keyFile(fileName);
418 if (!keyFile.isOpen())
419 keyFile.open(QIODevice::ReadOnly);
422 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
423 QVERIFY(!key.isNull()); // null passphrase => should be able to decode key
426 if (!keyFile.isOpen())
427 keyFile.open(QIODevice::ReadOnly);
430 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
431 QVERIFY(!key.isNull()); // empty passphrase => should be able to decode key
434 if (!keyFile.isOpen())
435 keyFile.open(QIODevice::ReadOnly);
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
446 QTEST_MAIN(tst_QSslKey)
447 #include "tst_qsslkey.moc"