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>
50 class tst_QSslKey : public QObject
56 QSsl::KeyAlgorithm algorithm;
59 QSsl::EncodingFormat format;
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)
67 QList<KeyInfo> keyInfoList;
69 void createPlainTestRows();
73 virtual ~tst_QSslKey();
76 void initTestCase_data();
83 void emptyConstructor();
84 void constructor_data();
86 void copyAndAssign_data();
88 void equalsOperator();
91 void toPemOrDer_data();
93 void toEncryptedPemOrDer_data();
94 void toEncryptedPemOrDer();
96 void passphraseChecks();
100 tst_QSslKey::tst_QSslKey()
103 // applicationDirPath() points to a path inside the app bundle on Mac.
104 QDir dir(qApp->applicationDirPath() + QLatin1String("/../../../keys"));
106 QDir dir(SRCDIR + QLatin1String("/keys")); // prefer this way to avoid ifdeffery and support shadow builds?
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(
114 rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa : QSsl::Dsa,
115 rx.cap(2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
117 rx.cap(4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
121 tst_QSslKey::~tst_QSslKey()
125 void tst_QSslKey::initTestCase_data()
129 void tst_QSslKey::init()
133 void tst_QSslKey::cleanup()
137 static QByteArray readFile(const QString &absFilePath)
139 QFile file(absFilePath);
140 if (!file.open(QIODevice::ReadOnly)) {
141 QWARN("failed to open file");
144 return file.readAll();
147 #ifndef QT_NO_OPENSSL
149 void tst_QSslKey::emptyConstructor()
151 if (!QSslSocket::supportsSsl())
155 QVERIFY(key.isNull());
156 QVERIFY(key.length() < 0);
162 Q_DECLARE_METATYPE(QSsl::KeyAlgorithm)
163 Q_DECLARE_METATYPE(QSsl::KeyType)
164 Q_DECLARE_METATYPE(QSsl::EncodingFormat)
166 void tst_QSslKey::createPlainTestRows()
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;
180 void tst_QSslKey::constructor_data()
182 createPlainTestRows();
185 void tst_QSslKey::constructor()
187 if (!QSslSocket::supportsSsl())
190 QFETCH(QString, absFilePath);
191 QFETCH(QSsl::KeyAlgorithm, algorithm);
192 QFETCH(QSsl::KeyType, type);
193 QFETCH(QSsl::EncodingFormat, format);
195 QByteArray encoded = readFile(absFilePath);
196 QSslKey key(encoded, algorithm, format, type);
197 QVERIFY(!key.isNull());
200 void tst_QSslKey::copyAndAssign_data()
202 createPlainTestRows();
205 void tst_QSslKey::copyAndAssign()
207 if (!QSslSocket::supportsSsl())
210 QFETCH(QString, absFilePath);
211 QFETCH(QSsl::KeyAlgorithm, algorithm);
212 QFETCH(QSsl::KeyType, type);
213 QFETCH(QSsl::EncodingFormat, format);
215 QByteArray encoded = readFile(absFilePath);
216 QSslKey key(encoded, algorithm, format, type);
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());
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());
235 void tst_QSslKey::equalsOperator()
240 void tst_QSslKey::length_data()
242 createPlainTestRows();
245 void tst_QSslKey::length()
247 if (!QSslSocket::supportsSsl())
250 QFETCH(QString, absFilePath);
251 QFETCH(QSsl::KeyAlgorithm, algorithm);
252 QFETCH(QSsl::KeyType, type);
254 QFETCH(QSsl::EncodingFormat, format);
256 QByteArray encoded = readFile(absFilePath);
257 QSslKey key(encoded, algorithm, format, type);
258 QVERIFY(!key.isNull());
259 QCOMPARE(key.length(), length);
262 void tst_QSslKey::toPemOrDer_data()
264 createPlainTestRows();
267 void tst_QSslKey::toPemOrDer()
269 if (!QSslSocket::supportsSsl())
272 QFETCH(QString, absFilePath);
273 QFETCH(QSsl::KeyAlgorithm, algorithm);
274 QFETCH(QSsl::KeyType, type);
275 QFETCH(QSsl::EncodingFormat, format);
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);
285 void tst_QSslKey::toEncryptedPemOrDer_data()
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");
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;
309 void tst_QSslKey::toEncryptedPemOrDer()
311 if (!QSslSocket::supportsSsl())
314 QFETCH(QString, absFilePath);
315 QFETCH(QSsl::KeyAlgorithm, algorithm);
316 QFETCH(QSsl::KeyType, type);
317 QFETCH(QSsl::EncodingFormat, format);
318 QFETCH(QString, password);
320 QByteArray plain = readFile(absFilePath);
321 QSslKey key(plain, algorithm, format, type);
322 QVERIFY(!key.isNull());
324 QByteArray pwBytes(password.toLatin1());
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());
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);
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)
349 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
350 QVERIFY(!keyDer.isNull());
351 if (type == QSsl::PrivateKey)
353 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
354 QCOMPARE(keyDer.toPem(), key.toPem());
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);
364 // ### add a test to verify that public keys are _decrypted_ correctly (by the ctor)
367 void tst_QSslKey::passphraseChecks()
370 QString fileName(SRCDIR "/rsa-with-passphrase.pem");
371 QFile keyFile(fileName);
372 QVERIFY(keyFile.exists());
374 if (!keyFile.isOpen())
375 keyFile.open(QIODevice::ReadOnly);
378 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
379 QVERIFY(key.isNull()); // null passphrase => should not be able to decode key
382 if (!keyFile.isOpen())
383 keyFile.open(QIODevice::ReadOnly);
386 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
387 QVERIFY(key.isNull()); // empty passphrase => should not be able to decode key
390 if (!keyFile.isOpen())
391 keyFile.open(QIODevice::ReadOnly);
394 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!");
395 QVERIFY(key.isNull()); // wrong passphrase => should not be able to decode key
398 if (!keyFile.isOpen())
399 keyFile.open(QIODevice::ReadOnly);
402 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123");
403 QVERIFY(!key.isNull()); // correct passphrase
408 // be sure and check a key without passphrase too
409 QString fileName(SRCDIR "/rsa-without-passphrase.pem");
410 QFile keyFile(fileName);
412 if (!keyFile.isOpen())
413 keyFile.open(QIODevice::ReadOnly);
416 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
417 QVERIFY(!key.isNull()); // null passphrase => should be able to decode key
420 if (!keyFile.isOpen())
421 keyFile.open(QIODevice::ReadOnly);
424 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
425 QVERIFY(!key.isNull()); // empty passphrase => should be able to decode key
428 if (!keyFile.isOpen())
429 keyFile.open(QIODevice::ReadOnly);
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
440 QTEST_MAIN(tst_QSslKey)
441 #include "tst_qsslkey.moc"