1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
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();
77 void emptyConstructor();
78 void constructor_data();
80 void copyAndAssign_data();
82 void equalsOperator();
85 void toPemOrDer_data();
87 void toEncryptedPemOrDer_data();
88 void toEncryptedPemOrDer();
90 void passphraseChecks();
96 void tst_QSslKey::initTestCase()
98 testDataDir = QFileInfo(QFINDTESTDATA("rsa-without-passphrase.pem")).absolutePath();
99 if (testDataDir.isEmpty())
100 testDataDir = QCoreApplication::applicationDirPath();
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(
109 rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa : QSsl::Dsa,
110 rx.cap(2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
112 rx.cap(4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
118 static QByteArray readFile(const QString &absFilePath)
120 QFile file(absFilePath);
121 if (!file.open(QIODevice::ReadOnly)) {
122 QWARN("failed to open file");
125 return file.readAll();
128 void tst_QSslKey::emptyConstructor()
130 if (!QSslSocket::supportsSsl())
134 QVERIFY(key.isNull());
135 QVERIFY(key.length() < 0);
141 Q_DECLARE_METATYPE(QSsl::KeyAlgorithm)
142 Q_DECLARE_METATYPE(QSsl::KeyType)
143 Q_DECLARE_METATYPE(QSsl::EncodingFormat)
145 void tst_QSslKey::createPlainTestRows()
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;
159 void tst_QSslKey::constructor_data()
161 createPlainTestRows();
164 void tst_QSslKey::constructor()
166 if (!QSslSocket::supportsSsl())
169 QFETCH(QString, absFilePath);
170 QFETCH(QSsl::KeyAlgorithm, algorithm);
171 QFETCH(QSsl::KeyType, type);
172 QFETCH(QSsl::EncodingFormat, format);
174 QByteArray encoded = readFile(absFilePath);
175 QSslKey key(encoded, algorithm, format, type);
176 QVERIFY(!key.isNull());
179 void tst_QSslKey::copyAndAssign_data()
181 createPlainTestRows();
184 void tst_QSslKey::copyAndAssign()
186 if (!QSslSocket::supportsSsl())
189 QFETCH(QString, absFilePath);
190 QFETCH(QSsl::KeyAlgorithm, algorithm);
191 QFETCH(QSsl::KeyType, type);
192 QFETCH(QSsl::EncodingFormat, format);
194 QByteArray encoded = readFile(absFilePath);
195 QSslKey key(encoded, algorithm, format, type);
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());
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());
214 void tst_QSslKey::equalsOperator()
219 void tst_QSslKey::length_data()
221 createPlainTestRows();
224 void tst_QSslKey::length()
226 if (!QSslSocket::supportsSsl())
229 QFETCH(QString, absFilePath);
230 QFETCH(QSsl::KeyAlgorithm, algorithm);
231 QFETCH(QSsl::KeyType, type);
233 QFETCH(QSsl::EncodingFormat, format);
235 QByteArray encoded = readFile(absFilePath);
236 QSslKey key(encoded, algorithm, format, type);
237 QVERIFY(!key.isNull());
238 QCOMPARE(key.length(), length);
241 void tst_QSslKey::toPemOrDer_data()
243 createPlainTestRows();
246 void tst_QSslKey::toPemOrDer()
248 if (!QSslSocket::supportsSsl())
251 QFETCH(QString, absFilePath);
252 QFETCH(QSsl::KeyAlgorithm, algorithm);
253 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 if (format == QSsl::Pem)
260 encoded.replace('\r', "");
261 QCOMPARE(format == QSsl::Pem ? key.toPem() : key.toDer(), encoded);
264 void tst_QSslKey::toEncryptedPemOrDer_data()
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");
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")
282 QTest::newRow(testName.toLatin1())
283 << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
284 << keyInfo.format << password;
289 void tst_QSslKey::toEncryptedPemOrDer()
291 if (!QSslSocket::supportsSsl())
294 QFETCH(QString, absFilePath);
295 QFETCH(QSsl::KeyAlgorithm, algorithm);
296 QFETCH(QSsl::KeyType, type);
297 QFETCH(QSsl::EncodingFormat, format);
298 QFETCH(QString, password);
300 QByteArray plain = readFile(absFilePath);
301 QSslKey key(plain, algorithm, format, type);
302 QVERIFY(!key.isNull());
304 QByteArray pwBytes(password.toLatin1());
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());
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);
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)
329 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
330 QVERIFY(!keyDer.isNull());
331 if (type == QSsl::PrivateKey)
333 QTest::currentDataTag(), "We're not able to decrypt these yet...", Continue);
334 QCOMPARE(keyDer.toPem(), key.toPem());
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);
344 // ### add a test to verify that public keys are _decrypted_ correctly (by the ctor)
347 void tst_QSslKey::passphraseChecks()
350 QString fileName(testDataDir + "/rsa-with-passphrase.pem");
351 QFile keyFile(fileName);
352 QVERIFY(keyFile.exists());
354 if (!keyFile.isOpen())
355 keyFile.open(QIODevice::ReadOnly);
358 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
359 QVERIFY(key.isNull()); // null passphrase => should not be able to decode key
362 if (!keyFile.isOpen())
363 keyFile.open(QIODevice::ReadOnly);
366 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
367 QVERIFY(key.isNull()); // empty passphrase => should not be able to decode key
370 if (!keyFile.isOpen())
371 keyFile.open(QIODevice::ReadOnly);
374 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!");
375 QVERIFY(key.isNull()); // wrong passphrase => should not be able to decode key
378 if (!keyFile.isOpen())
379 keyFile.open(QIODevice::ReadOnly);
382 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123");
383 QVERIFY(!key.isNull()); // correct passphrase
388 // be sure and check a key without passphrase too
389 QString fileName(testDataDir + "/rsa-without-passphrase.pem");
390 QFile keyFile(fileName);
392 if (!keyFile.isOpen())
393 keyFile.open(QIODevice::ReadOnly);
396 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
397 QVERIFY(!key.isNull()); // null passphrase => should be able to decode key
400 if (!keyFile.isOpen())
401 keyFile.open(QIODevice::ReadOnly);
404 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
405 QVERIFY(!key.isNull()); // empty passphrase => should be able to decode key
408 if (!keyFile.isOpen())
409 keyFile.open(QIODevice::ReadOnly);
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
420 QTEST_MAIN(tst_QSslKey)
421 #include "tst_qsslkey.moc"