1/**
2 * Copyright (C) 2006 Brad Hards <bradh@frogmouth.net>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <QtCrypto>
27#include <QtTest/QtTest>
28
29#ifdef QT_STATICPLUGIN
30#include "import_plugins.h"
31#endif
32
33#include <openssl/opensslv.h>
34
35class CMSut : public QObject
36{
37 Q_OBJECT
38
39private Q_SLOTS:
40 void initTestCase();
41 void cleanupTestCase();
42 void xcrypt_data();
43 void xcrypt();
44 void signverify_data();
45 void signverify();
46 void signverify_message_data();
47 void signverify_message();
48 void signverify_message_invalid_data();
49 void signverify_message_invalid();
50
51private:
52 QCA::Initializer *m_init;
53};
54
55void CMSut::initTestCase()
56{
57 m_init = new QCA::Initializer;
58}
59
60void CMSut::cleanupTestCase()
61{
62 delete m_init;
63}
64
65void CMSut::xcrypt_data()
66{
67 QTest::addColumn<QByteArray>(name: "testText");
68
69 QTest::newRow(dataTag: "empty") << QByteArray("");
70 QTest::newRow(dataTag: "0") << QByteArray("0");
71 QTest::newRow(dataTag: "07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
72 QTest::newRow(dataTag: "dubious") << QByteArray("~!#**$#&&%^@#^&()");
73}
74
75void CMSut::xcrypt()
76{
77 QStringList providersToTest;
78 providersToTest.append(QStringLiteral("qca-ossl"));
79
80 foreach (const QString provider, providersToTest) {
81 if (!QCA::isSupported(features: "cert", provider))
82 QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
83 else if (!QCA::isSupported(features: "cms", provider))
84 QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
85 else {
86 QCA::Certificate pubCert =
87 QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), result: nullptr, provider);
88 QCOMPARE(pubCert.isNull(), false);
89
90 QCA::SecureMessageKey secMsgKey;
91 QCA::CertificateChain chain;
92 chain += pubCert;
93 secMsgKey.setX509CertificateChain(chain);
94
95 QCA::CMS cms;
96 QCA::SecureMessage msg(&cms);
97 QCOMPARE(msg.canClearsign(), false);
98 QCOMPARE(msg.canSignAndEncrypt(), false);
99 QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
100
101 msg.setRecipient(secMsgKey);
102
103 QFETCH(QByteArray, testText);
104
105 msg.startEncrypt();
106 msg.update(in: testText);
107 msg.end();
108
109 msg.waitForFinished(msecs: -1);
110
111 QByteArray encryptedResult1 = msg.read();
112 QCOMPARE(encryptedResult1.isEmpty(), false);
113
114 msg.reset();
115 msg.setRecipient(secMsgKey);
116 msg.startEncrypt();
117 msg.update(in: testText);
118 msg.end();
119
120 msg.waitForFinished(msecs: -1);
121 QVERIFY(msg.success());
122
123 QByteArray encryptedResult2 = msg.read();
124 QCOMPARE(encryptedResult2.isEmpty(), false);
125
126 QCA::ConvertResult res;
127 QCA::SecureArray passPhrase = "start";
128 QCA::PrivateKey privKey =
129 QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passphrase: passPhrase, result: &res);
130 QCOMPARE(res, QCA::ConvertGood);
131
132 secMsgKey.setX509PrivateKey(privKey);
133 QCA::SecureMessageKeyList privKeyList;
134 privKeyList += secMsgKey;
135 QCA::CMS cms2;
136 cms2.setPrivateKeys(privKeyList);
137
138 QCA::SecureMessage msg2(&cms2);
139
140 msg2.startDecrypt();
141 msg2.update(in: encryptedResult1);
142 msg2.end();
143 msg2.waitForFinished(msecs: -1);
144 QVERIFY(msg2.success());
145 QByteArray decryptedResult1 = msg2.read();
146 QCOMPARE(decryptedResult1, testText);
147
148 msg2.reset();
149 msg2.startDecrypt();
150 msg2.update(in: encryptedResult1);
151 msg2.end();
152 msg2.waitForFinished(msecs: -1);
153 QVERIFY(msg2.success());
154 QByteArray decryptedResult2 = msg2.read();
155
156 QCOMPARE(decryptedResult1, decryptedResult2);
157
158 QCOMPARE(msg2.canClearsign(), false);
159 QCOMPARE(msg2.canSignAndEncrypt(), false);
160 QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
161 }
162 }
163}
164
165void CMSut::signverify_data()
166{
167 QTest::addColumn<QByteArray>(name: "testText");
168
169 QTest::newRow(dataTag: "empty") << QByteArray("");
170 QTest::newRow(dataTag: "0") << QByteArray("0");
171 QTest::newRow(dataTag: "07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
172 QTest::newRow(dataTag: "dubious") << QByteArray("~!#**$#&&%^@#^&()");
173}
174
175// This one tests Detached format.
176void CMSut::signverify()
177{
178 QStringList providersToTest;
179 providersToTest.append(QStringLiteral("qca-ossl"));
180
181 foreach (const QString provider, providersToTest) {
182 if (!QCA::isSupported(features: "cert", provider))
183 QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
184 else if (!QCA::isSupported(features: "cms", provider))
185 QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
186 else {
187 QCA::ConvertResult res;
188 QCA::SecureArray passPhrase = "start";
189 QCA::PrivateKey privKey =
190 QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passphrase: passPhrase, result: &res, provider);
191 QCOMPARE(res, QCA::ConvertGood);
192
193 QCA::Certificate pubCert =
194 QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), result: &res, provider);
195 QCOMPARE(res, QCA::ConvertGood);
196 QCOMPARE(pubCert.isNull(), false);
197
198 QCA::CertificateChain chain;
199 chain += pubCert;
200 QCA::SecureMessageKey secMsgKey;
201 secMsgKey.setX509CertificateChain(chain);
202 secMsgKey.setX509PrivateKey(privKey);
203
204 QCA::SecureMessageKeyList privKeyList;
205 privKeyList += secMsgKey;
206 QCA::CMS cms2;
207 cms2.setPrivateKeys(privKeyList);
208
209 QCA::SecureMessage msg2(&cms2);
210 msg2.setSigners(privKeyList);
211 QCOMPARE(msg2.canClearsign(), false);
212 QCOMPARE(msg2.canSignAndEncrypt(), false);
213 QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
214
215 QFETCH(QByteArray, testText);
216
217 msg2.startSign(m: QCA::SecureMessage::Detached);
218 msg2.update(in: testText);
219 msg2.end();
220 msg2.waitForFinished(msecs: -1);
221 QVERIFY(msg2.success());
222 QByteArray signedResult1 = msg2.signature();
223 QCOMPARE(signedResult1.isEmpty(), false);
224
225 msg2.reset();
226
227 msg2.setSigners(privKeyList);
228 msg2.startSign(m: QCA::SecureMessage::Detached);
229 msg2.update(in: testText);
230 msg2.end();
231 msg2.waitForFinished(msecs: -1);
232 QVERIFY(msg2.success());
233 QByteArray signedResult2 = msg2.signature();
234
235 QCOMPARE(signedResult2.isEmpty(), false);
236
237 QCA::CMS cms;
238 QCA::Certificate caCert =
239 QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), result: &res, provider);
240 QCOMPARE(res, QCA::ConvertGood);
241 QCA::CertificateCollection caCertCollection;
242 caCertCollection.addCertificate(cert: caCert);
243
244 cms.setTrustedCertificates(caCertCollection);
245 QCA::SecureMessage msg(&cms);
246 QCOMPARE(msg.canClearsign(), false);
247 QCOMPARE(msg.canSignAndEncrypt(), false);
248 QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
249
250 msg.startVerify(detachedSig: signedResult1);
251 msg.update(in: testText);
252 msg.end();
253
254 msg.waitForFinished(msecs: -1);
255 QVERIFY(msg.wasSigned());
256 QVERIFY(msg.success());
257#if OPENSSL_VERSION_NUMBER < 0x1010109fL
258 QEXPECT_FAIL("empty", "We don't seem to be able to verify signature of a zero length message", Continue);
259#endif
260 QVERIFY(msg.verifySuccess());
261
262 msg.reset();
263
264 msg.startVerify(detachedSig: signedResult2);
265 msg.update(in: testText);
266 msg.end();
267
268 msg.waitForFinished(msecs: -1);
269 QVERIFY(msg.wasSigned());
270 QVERIFY(msg.success());
271#if OPENSSL_VERSION_NUMBER < 0x1010109fL
272 QEXPECT_FAIL("empty", "We don't seem to be able to verify signature of a zero length message", Continue);
273#endif
274 QVERIFY(msg.verifySuccess());
275
276 msg.reset();
277
278 // This tests junk on the end of the signature - should fail
279 msg.startVerify(detachedSig: signedResult2 + "junk");
280 msg.update(in: testText);
281 msg.end();
282
283 msg.waitForFinished(msecs: -1);
284 QVERIFY(msg.wasSigned());
285 QVERIFY(msg.success());
286#if OPENSSL_VERSION_NUMBER >= 0x1010109fL
287 QEXPECT_FAIL("empty", "On newer openssl verifaction of zero length message always succeeds", Continue);
288#endif
289 QCOMPARE(msg.verifySuccess(), false);
290
291 msg.reset();
292
293 // This tests junk on the end of the message - should fail
294 msg.startVerify(detachedSig: signedResult2);
295 msg.update(in: testText + "junk");
296 msg.end();
297
298 msg.waitForFinished(msecs: -1);
299 QVERIFY(msg.wasSigned());
300 QVERIFY(msg.success());
301 QCOMPARE(msg.verifySuccess(), false);
302 }
303 }
304}
305
306void CMSut::signverify_message_data()
307{
308 QTest::addColumn<QByteArray>(name: "testText");
309
310 QTest::newRow(dataTag: "empty") << QByteArray("");
311 QTest::newRow(dataTag: "0") << QByteArray("0");
312 QTest::newRow(dataTag: "07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
313 QTest::newRow(dataTag: "dubious") << QByteArray("~!#**$#&&%^@#^&()");
314}
315
316// This one tests Message format
317void CMSut::signverify_message()
318{
319 QStringList providersToTest;
320 providersToTest.append(QStringLiteral("qca-ossl"));
321
322 foreach (const QString provider, providersToTest) {
323 if (!QCA::isSupported(features: "cert", provider))
324 QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
325 else if (!QCA::isSupported(features: "cms", provider))
326 QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
327 else {
328 QCA::ConvertResult res;
329 QCA::SecureArray passPhrase = "start";
330 QCA::PrivateKey privKey =
331 QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passphrase: passPhrase, result: &res, provider);
332 QCOMPARE(res, QCA::ConvertGood);
333
334 QCA::Certificate pubCert =
335 QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), result: &res, provider);
336 QCOMPARE(res, QCA::ConvertGood);
337 QCOMPARE(pubCert.isNull(), false);
338
339 QCA::CertificateChain chain;
340 chain += pubCert;
341 QCA::SecureMessageKey secMsgKey;
342 secMsgKey.setX509CertificateChain(chain);
343 secMsgKey.setX509PrivateKey(privKey);
344
345 QCA::SecureMessageKeyList privKeyList;
346 privKeyList += secMsgKey;
347 QCA::CMS cms2;
348 cms2.setPrivateKeys(privKeyList);
349
350 QCA::SecureMessage msg2(&cms2);
351 msg2.setSigners(privKeyList);
352 QCOMPARE(msg2.canClearsign(), false);
353 QCOMPARE(msg2.canSignAndEncrypt(), false);
354 QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
355
356 QFETCH(QByteArray, testText);
357
358 msg2.startSign(m: QCA::SecureMessage::Message);
359 msg2.update(in: testText);
360 msg2.end();
361 msg2.waitForFinished(msecs: -1);
362 QVERIFY(msg2.success());
363 QByteArray signedResult1 = msg2.read();
364 QCOMPARE(signedResult1.isEmpty(), false);
365
366 msg2.reset();
367
368 msg2.setSigners(privKeyList);
369 msg2.startSign(m: QCA::SecureMessage::Message);
370 msg2.update(in: testText);
371 msg2.end();
372 msg2.waitForFinished(msecs: -1);
373 QVERIFY(msg2.success());
374 QByteArray signedResult2 = msg2.read();
375
376 QCOMPARE(signedResult2.isEmpty(), false);
377
378 QCA::CMS cms;
379 QCA::Certificate caCert =
380 QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), result: &res, provider);
381 QCOMPARE(res, QCA::ConvertGood);
382
383 QCA::CertificateCollection caCertCollection;
384 caCertCollection.addCertificate(cert: caCert);
385
386 cms.setTrustedCertificates(caCertCollection);
387 QCA::SecureMessage msg(&cms);
388 QCOMPARE(msg.canClearsign(), false);
389 QCOMPARE(msg.canSignAndEncrypt(), false);
390 QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
391
392 msg.startVerify();
393 msg.update(in: signedResult1);
394 msg.end();
395
396 msg.waitForFinished(msecs: -1);
397 QVERIFY(msg.wasSigned());
398 QVERIFY(msg.success());
399 QVERIFY(msg.verifySuccess());
400
401 msg.reset();
402
403 msg.startVerify();
404 msg.update(in: signedResult2);
405 msg.end();
406
407 msg.waitForFinished(msecs: -1);
408 QVERIFY(msg.wasSigned());
409 QVERIFY(msg.success());
410 QVERIFY(msg.verifySuccess());
411
412 msg.reset();
413
414 msg.startVerify();
415 msg.update(in: signedResult2);
416 msg.end();
417
418 msg.waitForFinished(msecs: -1);
419 QVERIFY(msg.wasSigned());
420 QVERIFY(msg.success());
421 QCOMPARE(msg.verifySuccess(), true);
422 }
423 }
424}
425
426void CMSut::signverify_message_invalid_data()
427{
428 QTest::addColumn<QByteArray>(name: "testText");
429
430 QTest::newRow(dataTag: "empty") << QByteArray("");
431 QTest::newRow(dataTag: "0") << QByteArray("0");
432 QTest::newRow(dataTag: "07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01");
433 QTest::newRow(dataTag: "dubious") << QByteArray("~!#**$#&&%^@#^&()");
434}
435
436// This one tests Message format
437void CMSut::signverify_message_invalid()
438{
439 QStringList providersToTest;
440 providersToTest.append(QStringLiteral("qca-ossl"));
441
442 foreach (const QString provider, providersToTest) {
443 if (!QCA::isSupported(features: "cert", provider))
444 QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData());
445 else if (!QCA::isSupported(features: "cms", provider))
446 QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData());
447 else {
448 QCA::ConvertResult res;
449 QCA::SecureArray passPhrase = "start";
450 QCA::PrivateKey privKey =
451 QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passphrase: passPhrase, result: &res, provider);
452 QCOMPARE(res, QCA::ConvertGood);
453
454 QCA::Certificate pubCert =
455 QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), result: &res, provider);
456 QCOMPARE(res, QCA::ConvertGood);
457 QCOMPARE(pubCert.isNull(), false);
458
459 QCA::CertificateChain chain;
460 chain += pubCert;
461 QCA::SecureMessageKey secMsgKey;
462 secMsgKey.setX509CertificateChain(chain);
463 secMsgKey.setX509PrivateKey(privKey);
464
465 QCA::SecureMessageKeyList privKeyList;
466 privKeyList += secMsgKey;
467 QCA::CMS cms2;
468 cms2.setPrivateKeys(privKeyList);
469
470 QCA::SecureMessage msg2(&cms2);
471 msg2.setSigners(privKeyList);
472 QCOMPARE(msg2.canClearsign(), false);
473 QCOMPARE(msg2.canSignAndEncrypt(), false);
474 QCOMPARE(msg2.type(), QCA::SecureMessage::CMS);
475
476 QFETCH(QByteArray, testText);
477
478 msg2.startSign(m: QCA::SecureMessage::Message);
479 msg2.update(in: testText);
480 msg2.end();
481 msg2.waitForFinished(msecs: -1);
482 QVERIFY(msg2.success());
483 QByteArray signedResult1 = msg2.read();
484 QCOMPARE(signedResult1.isEmpty(), false);
485
486 QCA::CMS cms;
487 QCA::Certificate caCert =
488 QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), result: &res, provider);
489 QCOMPARE(res, QCA::ConvertGood);
490
491 QCA::CertificateCollection caCertCollection;
492 caCertCollection.addCertificate(cert: caCert);
493
494 cms.setTrustedCertificates(caCertCollection);
495 QCA::SecureMessage msg(&cms);
496 QCOMPARE(msg.canClearsign(), false);
497 QCOMPARE(msg.canSignAndEncrypt(), false);
498 QCOMPARE(msg.type(), QCA::SecureMessage::CMS);
499
500 // This is just to break things
501 // signedResult1[30] = signedResult1[30] + 1;
502 if (signedResult1.at(i: signedResult1.size() - 2) != 0) {
503 signedResult1[signedResult1.size() - 2] = 0x00;
504 } else {
505 signedResult1[signedResult1.size() - 2] = 0x01;
506 }
507
508 msg.startVerify();
509 msg.update(in: signedResult1);
510 msg.end();
511
512 msg.waitForFinished(msecs: -1);
513 QVERIFY(msg.wasSigned());
514 QVERIFY(msg.success());
515 QCOMPARE(msg.verifySuccess(), false);
516 }
517 }
518}
519
520QTEST_MAIN(CMSut)
521
522#include "cms.moc"
523

source code of qca/unittest/cms/cms.cpp