1/*
2 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
3 * Copyright (C) 2004,2005 Brad Hards <bradh@frogmouth.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include "qca_core.h"
23
24#include "qca_cert.h"
25#include "qca_textfilter.h"
26#include "qcaprovider.h"
27#include <QMutex>
28
29#ifndef QCA_NO_SYSTEMSTORE
30#include "qca_systemstore.h"
31#endif
32
33#include <cstdlib>
34
35#define FRIENDLY_NAMES
36
37namespace QCA {
38
39class DefaultShared
40{
41private:
42 mutable QMutex m;
43 bool _use_system;
44 QString _roots_file;
45 QStringList _skip_plugins;
46 QStringList _plugin_priorities;
47
48public:
49 DefaultShared()
50 : _use_system(true)
51 {
52 }
53
54 bool use_system() const
55 {
56 QMutexLocker locker(&m);
57 return _use_system;
58 }
59
60 QString roots_file() const
61 {
62 QMutexLocker locker(&m);
63 return _roots_file;
64 }
65
66 QStringList skip_plugins() const
67 {
68 QMutexLocker locker(&m);
69 return _skip_plugins;
70 }
71
72 QStringList plugin_priorities() const
73 {
74 QMutexLocker locker(&m);
75 return _plugin_priorities;
76 }
77
78 void set(bool use_system,
79 const QString &roots_file,
80 const QStringList &skip_plugins,
81 const QStringList &plugin_priorities)
82 {
83 QMutexLocker locker(&m);
84 _use_system = use_system;
85 _roots_file = roots_file;
86 _skip_plugins = skip_plugins;
87 _plugin_priorities = plugin_priorities;
88 }
89};
90
91//----------------------------------------------------------------------------
92// DefaultRandomContext
93//----------------------------------------------------------------------------
94class DefaultRandomContext : public RandomContext
95{
96 Q_OBJECT
97public:
98 DefaultRandomContext(Provider *p)
99 : RandomContext(p)
100 {
101 }
102
103 Provider::Context *clone() const override
104 {
105 return new DefaultRandomContext(provider());
106 }
107
108 SecureArray nextBytes(int size) override
109 {
110 SecureArray buf(size);
111 for (int n = 0; n < (int)buf.size(); ++n)
112 buf[n] = (char)std::rand();
113 return buf;
114 }
115};
116
117//----------------------------------------------------------------------------
118// DefaultMD5Context
119//----------------------------------------------------------------------------
120
121/* NOTE: the following code was modified to not need BYTE_ORDER -- Justin */
122
123/*
124 Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
125
126 This software is provided 'as-is', without any express or implied
127 warranty. In no event will the authors be held liable for any damages
128 arising from the use of this software.
129
130 Permission is granted to anyone to use this software for any purpose,
131 including commercial applications, and to alter it and redistribute it
132 freely, subject to the following restrictions:
133
134 1. The origin of this software must not be misrepresented; you must not
135 claim that you wrote the original software. If you use this software
136 in a product, an acknowledgment in the product documentation would be
137 appreciated but is not required.
138 2. Altered source versions must be plainly marked as such, and must not be
139 misrepresented as being the original software.
140 3. This notice may not be removed or altered from any source distribution.
141
142 L. Peter Deutsch
143 ghost@aladdin.com
144
145 */
146/* $Id$ */
147/*
148 Independent implementation of MD5 (RFC 1321).
149
150 This code implements the MD5 Algorithm defined in RFC 1321, whose
151 text is available at
152 http://www.ietf.org/rfc/rfc1321.txt
153 The code is derived from the text of the RFC, including the test suite
154 (section A.5) but excluding the rest of Appendix A. It does not include
155 any code or documentation that is identified in the RFC as being
156 copyrighted.
157
158 The original and principal author of md5.c is L. Peter Deutsch
159 <ghost@aladdin.com>. Other authors are noted in the change history
160 that follows (in reverse chronological order):
161
162 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
163 either statically or dynamically; added missing #include <string.h>
164 in library.
165 2002-03-11 lpd Corrected argument list for main(), and added int return
166 type, in test program and T value program.
167 2002-02-21 lpd Added missing #include <stdio.h> in test program.
168 2000-07-03 lpd Patched to eliminate warnings about "constant is
169 unsigned in ANSI C, signed in traditional"; made test program
170 self-checking.
171 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
172 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
173 1999-05-03 lpd Original version.
174 */
175
176/*
177 * This package supports both compile-time and run-time determination of CPU
178 * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
179 * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
180 * defined as non-zero, the code will be compiled to run only on big-endian
181 * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
182 * run on either big- or little-endian CPUs, but will run slightly less
183 * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
184 */
185
186typedef quint8 md5_byte_t; /* 8-bit byte */
187typedef quint32 md5_word_t; /* 32-bit word */
188
189/* Define the state of the MD5 Algorithm. */
190struct md5_state_t
191{
192 md5_word_t count[2]; // 2 /* message length in bits, lsw first */
193 md5_word_t abcd[4]; // 4 /* digest buffer */
194 md5_byte_t buf[64]; // 64 /* accumulate block */
195
196 md5_state_t()
197 {
198 memset(s: count, c: 0, n: sizeof(count));
199 memset(s: abcd, c: 0, n: sizeof(abcd));
200 memset(s: buf, c: 0, n: sizeof(buf));
201 }
202};
203
204/* Initialize the algorithm. */
205void md5_init(md5_state_t *pms);
206
207/* Append a string to the message. */
208void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
209
210/* Finish the message and return the digest. */
211void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
212
213#define T_MASK ((md5_word_t)~0)
214#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
215#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
216#define T3 0x242070db
217#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
218#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
219#define T6 0x4787c62a
220#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
221#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
222#define T9 0x698098d8
223#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
224#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
225#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
226#define T13 0x6b901122
227#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
228#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
229#define T16 0x49b40821
230#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
231#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
232#define T19 0x265e5a51
233#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
234#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
235#define T22 0x02441453
236#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
237#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
238#define T25 0x21e1cde6
239#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
240#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
241#define T28 0x455a14ed
242#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
243#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
244#define T31 0x676f02d9
245#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
246#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
247#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
248#define T35 0x6d9d6122
249#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
250#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
251#define T38 0x4bdecfa9
252#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
253#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
254#define T41 0x289b7ec6
255#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
256#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
257#define T44 0x04881d05
258#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
259#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
260#define T47 0x1fa27cf8
261#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
262#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
263#define T50 0x432aff97
264#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
265#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
266#define T53 0x655b59c3
267#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
268#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
269#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
270#define T57 0x6fa87e4f
271#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
272#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
273#define T60 0x4e0811a1
274#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
275#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
276#define T63 0x2ad7d2bb
277#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
278
279static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
280{
281 md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3];
282 md5_word_t t;
283
284 /* Define storage for little-endian or both types of CPUs. */
285 md5_word_t xbuf[16];
286 const md5_word_t *X;
287
288 {
289 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
290 /*
291 * On big-endian machines, we must arrange the bytes in the
292 * right order.
293 */
294 const md5_byte_t *xp = data;
295 int i;
296
297 X = xbuf; /* (dynamic only) */
298
299 for (i = 0; i < 16; ++i, xp += 4)
300 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
301 } else /* dynamic big-endian */
302 {
303 /*
304 * On little-endian machines, we can process properly aligned
305 * data without copying it. On arm do copying always
306 */
307#ifndef Q_PROCESSOR_ARM
308 if (!(reinterpret_cast<uintptr_t>(data) & 3)) {
309 /* data are properly aligned */
310 X = reinterpret_cast<const md5_word_t *>(data);
311 } else
312#endif
313 {
314 /* not aligned */
315 memcpy(dest: xbuf, src: data, n: 64);
316 X = xbuf;
317 }
318 }
319 }
320
321#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
322
323 /* Round 1. */
324 /* Let [abcd k s i] denote the operation
325 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
326#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
327#define SET(a, b, c, d, k, s, Ti) \
328 t = a + F(b, c, d) + X[k] + Ti; \
329 a = ROTATE_LEFT(t, s) + b
330 /* Do the following 16 operations. */
331 SET(a, b, c, d, 0, 7, T1);
332 SET(d, a, b, c, 1, 12, T2);
333 SET(c, d, a, b, 2, 17, T3);
334 SET(b, c, d, a, 3, 22, T4);
335 SET(a, b, c, d, 4, 7, T5);
336 SET(d, a, b, c, 5, 12, T6);
337 SET(c, d, a, b, 6, 17, T7);
338 SET(b, c, d, a, 7, 22, T8);
339 SET(a, b, c, d, 8, 7, T9);
340 SET(d, a, b, c, 9, 12, T10);
341 SET(c, d, a, b, 10, 17, T11);
342 SET(b, c, d, a, 11, 22, T12);
343 SET(a, b, c, d, 12, 7, T13);
344 SET(d, a, b, c, 13, 12, T14);
345 SET(c, d, a, b, 14, 17, T15);
346 SET(b, c, d, a, 15, 22, T16);
347#undef SET
348
349 /* Round 2. */
350 /* Let [abcd k s i] denote the operation
351 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
352#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
353#define SET(a, b, c, d, k, s, Ti) \
354 t = a + G(b, c, d) + X[k] + Ti; \
355 a = ROTATE_LEFT(t, s) + b
356 /* Do the following 16 operations. */
357 SET(a, b, c, d, 1, 5, T17);
358 SET(d, a, b, c, 6, 9, T18);
359 SET(c, d, a, b, 11, 14, T19);
360 SET(b, c, d, a, 0, 20, T20);
361 SET(a, b, c, d, 5, 5, T21);
362 SET(d, a, b, c, 10, 9, T22);
363 SET(c, d, a, b, 15, 14, T23);
364 SET(b, c, d, a, 4, 20, T24);
365 SET(a, b, c, d, 9, 5, T25);
366 SET(d, a, b, c, 14, 9, T26);
367 SET(c, d, a, b, 3, 14, T27);
368 SET(b, c, d, a, 8, 20, T28);
369 SET(a, b, c, d, 13, 5, T29);
370 SET(d, a, b, c, 2, 9, T30);
371 SET(c, d, a, b, 7, 14, T31);
372 SET(b, c, d, a, 12, 20, T32);
373#undef SET
374
375 /* Round 3. */
376 /* Let [abcd k s t] denote the operation
377 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
378#define H(x, y, z) ((x) ^ (y) ^ (z))
379#define SET(a, b, c, d, k, s, Ti) \
380 t = a + H(b, c, d) + X[k] + Ti; \
381 a = ROTATE_LEFT(t, s) + b
382 /* Do the following 16 operations. */
383 SET(a, b, c, d, 5, 4, T33);
384 SET(d, a, b, c, 8, 11, T34);
385 SET(c, d, a, b, 11, 16, T35);
386 SET(b, c, d, a, 14, 23, T36);
387 SET(a, b, c, d, 1, 4, T37);
388 SET(d, a, b, c, 4, 11, T38);
389 SET(c, d, a, b, 7, 16, T39);
390 SET(b, c, d, a, 10, 23, T40);
391 SET(a, b, c, d, 13, 4, T41);
392 SET(d, a, b, c, 0, 11, T42);
393 SET(c, d, a, b, 3, 16, T43);
394 SET(b, c, d, a, 6, 23, T44);
395 SET(a, b, c, d, 9, 4, T45);
396 SET(d, a, b, c, 12, 11, T46);
397 SET(c, d, a, b, 15, 16, T47);
398 SET(b, c, d, a, 2, 23, T48);
399#undef SET
400
401 /* Round 4. */
402 /* Let [abcd k s t] denote the operation
403 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
404#define I(x, y, z) ((y) ^ ((x) | ~(z)))
405#define SET(a, b, c, d, k, s, Ti) \
406 t = a + I(b, c, d) + X[k] + Ti; \
407 a = ROTATE_LEFT(t, s) + b
408 /* Do the following 16 operations. */
409 SET(a, b, c, d, 0, 6, T49);
410 SET(d, a, b, c, 7, 10, T50);
411 SET(c, d, a, b, 14, 15, T51);
412 SET(b, c, d, a, 5, 21, T52);
413 SET(a, b, c, d, 12, 6, T53);
414 SET(d, a, b, c, 3, 10, T54);
415 SET(c, d, a, b, 10, 15, T55);
416 SET(b, c, d, a, 1, 21, T56);
417 SET(a, b, c, d, 8, 6, T57);
418 SET(d, a, b, c, 15, 10, T58);
419 SET(c, d, a, b, 6, 15, T59);
420 SET(b, c, d, a, 13, 21, T60);
421 SET(a, b, c, d, 4, 6, T61);
422 SET(d, a, b, c, 11, 10, T62);
423 SET(c, d, a, b, 2, 15, T63);
424 SET(b, c, d, a, 9, 21, T64);
425#undef SET
426
427 /* Then perform the following additions. (That is increment each
428 of the four registers by the value it had before this block
429 was started.) */
430 pms->abcd[0] += a;
431 pms->abcd[1] += b;
432 pms->abcd[2] += c;
433 pms->abcd[3] += d;
434}
435
436void md5_init(md5_state_t *pms)
437{
438 pms->count[0] = pms->count[1] = 0;
439 pms->abcd[0] = 0x67452301;
440 pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
441 pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
442 pms->abcd[3] = 0x10325476;
443}
444
445void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
446{
447 const md5_byte_t *p = data;
448 int left = nbytes;
449 int offset = (pms->count[0] >> 3) & 63;
450 md5_word_t nbits = (md5_word_t)(nbytes << 3);
451
452 if (nbytes <= 0)
453 return;
454
455 /* Update the message length. */
456 pms->count[1] += nbytes >> 29;
457 pms->count[0] += nbits;
458 if (pms->count[0] < nbits)
459 pms->count[1]++;
460
461 /* Process an initial partial block. */
462 if (offset) {
463 int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
464
465 memcpy(dest: pms->buf + offset, src: p, n: copy);
466 if (offset + copy < 64)
467 return;
468 p += copy;
469 left -= copy;
470 md5_process(pms, data: pms->buf);
471 }
472
473 /* Process full blocks. */
474 for (; left >= 64; p += 64, left -= 64)
475 md5_process(pms, data: p);
476
477 /* Process a final partial block. */
478 if (left)
479 memcpy(dest: pms->buf, src: p, n: left);
480}
481
482void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
483{
484 static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
485 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
486 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
487 md5_byte_t data[8];
488 int i;
489
490 /* Save the length before padding. */
491 for (i = 0; i < 8; ++i)
492 data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
493 /* Pad to 56 bytes mod 64. */
494 md5_append(pms, data: pad, nbytes: ((55 - (pms->count[0] >> 3)) & 63) + 1);
495 /* Append the length. */
496 md5_append(pms, data, nbytes: 8);
497 for (i = 0; i < 16; ++i)
498 digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
499}
500
501class DefaultMD5Context : public HashContext
502{
503 Q_OBJECT
504public:
505 DefaultMD5Context(Provider *p)
506 : HashContext(p, QStringLiteral("md5"))
507 {
508 clear();
509 }
510
511 Provider::Context *clone() const override
512 {
513 return new DefaultMD5Context(*this);
514 }
515
516 void clear() override
517 {
518 secure = true;
519 md5_init(pms: &md5);
520 }
521
522 void update(const MemoryRegion &in) override
523 {
524 if (!in.isSecure())
525 secure = false;
526 md5_append(pms: &md5, data: (const md5_byte_t *)in.data(), nbytes: in.size());
527 }
528
529 MemoryRegion final() override
530 {
531 if (secure) {
532 SecureArray b(16, 0);
533 md5_finish(pms: &md5, digest: (md5_byte_t *)b.data());
534 return b;
535 } else {
536 QByteArray b(16, 0);
537 md5_finish(pms: &md5, digest: (md5_byte_t *)b.data());
538 return b;
539 }
540 }
541
542 bool secure;
543 md5_state_t md5;
544};
545
546//----------------------------------------------------------------------------
547// DefaultSHA1Context
548//----------------------------------------------------------------------------
549
550// SHA1 - from a public domain implementation by Steve Reid (steve@edmweb.com)
551
552#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
553
554#ifdef Q_PROCESSOR_ARM
555#define blk(i) \
556 (block.l[i & 15] = rol(block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^ block.l[i & 15], 1))
557#else
558#define blk(i) \
559 (block->l[i & 15] = \
560 rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))
561#endif
562
563/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
564#define R0(v, w, x, y, z, i) \
565 z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
566 w = rol(w, 30);
567#define R1(v, w, x, y, z, i) \
568 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
569 w = rol(w, 30);
570#define R2(v, w, x, y, z, i) \
571 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
572 w = rol(w, 30);
573#define R3(v, w, x, y, z, i) \
574 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
575 w = rol(w, 30);
576#define R4(v, w, x, y, z, i) \
577 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
578 w = rol(w, 30);
579
580struct SHA1_CONTEXT
581{
582 quint32 state[5]; // 5
583 quint32 count[2]; // 2
584 unsigned char buffer[64]; // 64
585
586 SHA1_CONTEXT()
587 {
588 memset(s: state, c: 0, n: sizeof(state));
589 memset(s: count, c: 0, n: sizeof(count));
590 memset(s: buffer, c: 0, n: sizeof(buffer));
591 }
592};
593
594typedef union {
595 unsigned char c[64];
596 quint32 l[16];
597} CHAR64LONG16;
598
599class DefaultSHA1Context : public HashContext
600{
601 Q_OBJECT
602public:
603 SHA1_CONTEXT _context;
604#ifdef Q_PROCESSOR_ARM
605 CHAR64LONG16 block;
606#else
607 CHAR64LONG16 *block;
608#endif
609 bool secure;
610
611 DefaultSHA1Context(Provider *p)
612 : HashContext(p, QStringLiteral("sha1"))
613 {
614 clear();
615 }
616
617 Provider::Context *clone() const override
618 {
619 return new DefaultSHA1Context(*this);
620 }
621
622 void clear() override
623 {
624 secure = true;
625 sha1_init(context: &_context);
626 }
627
628 void update(const MemoryRegion &in) override
629 {
630 if (!in.isSecure())
631 secure = false;
632 sha1_update(context: &_context, data: (unsigned char *)in.data(), len: (unsigned int)in.size());
633 }
634
635 MemoryRegion final() override
636 {
637 if (secure) {
638 SecureArray b(20, 0);
639 sha1_final(digest: (unsigned char *)b.data(), context: &_context);
640 return b;
641 } else {
642 QByteArray b(20, 0);
643 sha1_final(digest: (unsigned char *)b.data(), context: &_context);
644 return b;
645 }
646 }
647
648 inline unsigned long blk0(quint32 i)
649 {
650 if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
651#ifdef Q_PROCESSOR_ARM
652 return block.l[i];
653#else
654 return block->l[i];
655#endif
656 else
657#ifdef Q_PROCESSOR_ARM
658 return (block.l[i] = (rol(block.l[i], 24) & 0xFF00FF00) | (rol(block.l[i], 8) & 0x00FF00FF));
659#else
660 return (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF));
661#endif
662 }
663
664 // Hash a single 512-bit block. This is the core of the algorithm.
665 void transform(quint32 state[5], unsigned char buffer[64])
666 {
667 quint32 a, b, c, d, e;
668
669#ifdef Q_PROCESSOR_ARM
670 memcpy(&block, buffer, sizeof(block));
671#else
672 block = reinterpret_cast<CHAR64LONG16 *>(buffer);
673#endif
674 // Copy context->state[] to working vars
675 a = state[0];
676 b = state[1];
677 c = state[2];
678 d = state[3];
679 e = state[4];
680
681 // 4 rounds of 20 operations each. Loop unrolled.
682 R0(a, b, c, d, e, 0);
683 R0(e, a, b, c, d, 1);
684 R0(d, e, a, b, c, 2);
685 R0(c, d, e, a, b, 3);
686 R0(b, c, d, e, a, 4);
687 R0(a, b, c, d, e, 5);
688 R0(e, a, b, c, d, 6);
689 R0(d, e, a, b, c, 7);
690 R0(c, d, e, a, b, 8);
691 R0(b, c, d, e, a, 9);
692 R0(a, b, c, d, e, 10);
693 R0(e, a, b, c, d, 11);
694 R0(d, e, a, b, c, 12);
695 R0(c, d, e, a, b, 13);
696 R0(b, c, d, e, a, 14);
697 R0(a, b, c, d, e, 15);
698 R1(e, a, b, c, d, 16);
699 R1(d, e, a, b, c, 17);
700 R1(c, d, e, a, b, 18);
701 R1(b, c, d, e, a, 19);
702 R2(a, b, c, d, e, 20);
703 R2(e, a, b, c, d, 21);
704 R2(d, e, a, b, c, 22);
705 R2(c, d, e, a, b, 23);
706 R2(b, c, d, e, a, 24);
707 R2(a, b, c, d, e, 25);
708 R2(e, a, b, c, d, 26);
709 R2(d, e, a, b, c, 27);
710 R2(c, d, e, a, b, 28);
711 R2(b, c, d, e, a, 29);
712 R2(a, b, c, d, e, 30);
713 R2(e, a, b, c, d, 31);
714 R2(d, e, a, b, c, 32);
715 R2(c, d, e, a, b, 33);
716 R2(b, c, d, e, a, 34);
717 R2(a, b, c, d, e, 35);
718 R2(e, a, b, c, d, 36);
719 R2(d, e, a, b, c, 37);
720 R2(c, d, e, a, b, 38);
721 R2(b, c, d, e, a, 39);
722 R3(a, b, c, d, e, 40);
723 R3(e, a, b, c, d, 41);
724 R3(d, e, a, b, c, 42);
725 R3(c, d, e, a, b, 43);
726 R3(b, c, d, e, a, 44);
727 R3(a, b, c, d, e, 45);
728 R3(e, a, b, c, d, 46);
729 R3(d, e, a, b, c, 47);
730 R3(c, d, e, a, b, 48);
731 R3(b, c, d, e, a, 49);
732 R3(a, b, c, d, e, 50);
733 R3(e, a, b, c, d, 51);
734 R3(d, e, a, b, c, 52);
735 R3(c, d, e, a, b, 53);
736 R3(b, c, d, e, a, 54);
737 R3(a, b, c, d, e, 55);
738 R3(e, a, b, c, d, 56);
739 R3(d, e, a, b, c, 57);
740 R3(c, d, e, a, b, 58);
741 R3(b, c, d, e, a, 59);
742 R4(a, b, c, d, e, 60);
743 R4(e, a, b, c, d, 61);
744 R4(d, e, a, b, c, 62);
745 R4(c, d, e, a, b, 63);
746 R4(b, c, d, e, a, 64);
747 R4(a, b, c, d, e, 65);
748 R4(e, a, b, c, d, 66);
749 R4(d, e, a, b, c, 67);
750 R4(c, d, e, a, b, 68);
751 R4(b, c, d, e, a, 69);
752 R4(a, b, c, d, e, 70);
753 R4(e, a, b, c, d, 71);
754 R4(d, e, a, b, c, 72);
755 R4(c, d, e, a, b, 73);
756 R4(b, c, d, e, a, 74);
757 R4(a, b, c, d, e, 75);
758 R4(e, a, b, c, d, 76);
759 R4(d, e, a, b, c, 77);
760 R4(c, d, e, a, b, 78);
761 R4(b, c, d, e, a, 79);
762
763 // Add the working vars back into context.state[]
764 state[0] += a;
765 state[1] += b;
766 state[2] += c;
767 state[3] += d;
768 state[4] += e;
769
770 // Wipe variables
771 a = b = c = d = e = 0;
772 }
773
774 // SHA1Init - Initialize new context
775 void sha1_init(SHA1_CONTEXT *context)
776 {
777 // SHA1 initialization constants
778 context->state[0] = 0x67452301;
779 context->state[1] = 0xEFCDAB89;
780 context->state[2] = 0x98BADCFE;
781 context->state[3] = 0x10325476;
782 context->state[4] = 0xC3D2E1F0;
783 context->count[0] = context->count[1] = 0;
784 }
785
786 // Run your data through this
787 void sha1_update(SHA1_CONTEXT *context, unsigned char *data, quint32 len)
788 {
789 quint32 i, j;
790
791 j = (context->count[0] >> 3) & 63;
792 if ((context->count[0] += len << 3) < (len << 3))
793 context->count[1]++;
794
795 context->count[1] += (len >> 29);
796
797 if ((j + len) > 63) {
798 memcpy(dest: &context->buffer[j], src: data, n: (i = 64 - j));
799 transform(state: context->state, buffer: context->buffer);
800 for (; i + 63 < len; i += 64) {
801 transform(state: context->state, buffer: &data[i]);
802 }
803 j = 0;
804 } else
805 i = 0;
806 memcpy(dest: &context->buffer[j], src: &data[i], n: len - i);
807 }
808
809 // Add padding and return the message digest
810 void sha1_final(unsigned char digest[20], SHA1_CONTEXT *context)
811 {
812 quint32 i;
813 unsigned char finalcount[8];
814
815 for (i = 0; i < 8; i++) {
816 finalcount[i] =
817 (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent
818 }
819 sha1_update(context, data: (unsigned char *)"\200", len: 1);
820 while ((context->count[0] & 504) != 448) {
821 sha1_update(context, data: (unsigned char *)"\0", len: 1);
822 }
823 sha1_update(context, data: finalcount, len: 8); // Should cause a transform()
824 for (i = 0; i < 20; i++) {
825 digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
826 }
827
828 // Wipe variables
829 i = 0;
830 memset(s: context->buffer, c: 0, n: 64);
831 memset(s: context->state, c: 0, n: 20);
832 memset(s: context->count, c: 0, n: 8);
833 memset(s: &finalcount, c: 0, n: 8);
834 }
835};
836
837//----------------------------------------------------------------------------
838// DefaultKeyStoreEntry
839//----------------------------------------------------------------------------
840
841// this escapes colons, commas, and newlines. colons and commas so that they
842// are available as delimiters, and newlines so that our output can be a
843// single line of text.
844static QString escape_string(const QString &in)
845{
846 QString out;
847 for (const QChar &c : in) {
848 if (c == QLatin1Char('\\'))
849 out += QLatin1String("\\\\");
850 else if (c == QLatin1Char(':'))
851 out += QLatin1String("\\c");
852 else if (c == QLatin1Char(','))
853 out += QLatin1String("\\o");
854 else if (c == QLatin1Char('\n'))
855 out += QLatin1String("\\n");
856 else
857 out += c;
858 }
859 return out;
860}
861
862static bool unescape_string(const QString &in, QString *_out)
863{
864 QString out;
865 for (int n = 0; n < in.length(); ++n) {
866 if (in[n] == QLatin1Char('\\')) {
867 if (n + 1 >= in.length())
868 return false;
869
870 if (in[n + 1] == QLatin1Char('\\'))
871 out += QLatin1Char('\\');
872 else if (in[n + 1] == QLatin1Char('c'))
873 out += QLatin1Char(':');
874 else if (in[n + 1] == QLatin1Char('o'))
875 out += QLatin1Char(',');
876 else if (in[n + 1] == QLatin1Char('n'))
877 out += QLatin1Char('\n');
878 else
879 return false;
880 ++n;
881 } else
882 out += in[n];
883 }
884 *_out = out;
885 return true;
886}
887
888static QString escape_stringlist(const QStringList &in)
889{
890 QStringList list;
891 for (int n = 0; n < in.count(); ++n)
892 list += escape_string(in: in[n]);
893 return list.join(QStringLiteral(":"));
894}
895
896static bool unescape_stringlist(const QString &in, QStringList *_out)
897{
898 QStringList out;
899 const QStringList list = in.split(sep: QLatin1Char(':'));
900 for (int n = 0; n < list.count(); ++n) {
901 QString str;
902 if (!unescape_string(in: list[n], out: &str))
903 return false;
904 out += str;
905 }
906 *_out = out;
907 return true;
908}
909
910// serialization format is a colon separated list of 7 escaped strings
911// 0 - "qca_def_1" (header)
912// 1 - store id
913// 2 - store name
914// 3 - entry id
915// 4 - entry name
916// 5 - entry type (e.g. "cert")
917// 6 - string encoding of object (e.g. DER encoded in Base64)
918static QString entry_serialize(const QString &storeId,
919 const QString &storeName,
920 const QString &entryId,
921 const QString &entryName,
922 const QString &entryType,
923 const QString &data)
924{
925 QStringList out;
926 out += QStringLiteral("qca_def");
927 out += storeId;
928 out += storeName;
929 out += entryId;
930 out += entryName;
931 out += entryType;
932 out += data;
933 return escape_stringlist(in: out);
934}
935
936static bool entry_deserialize(const QString &in,
937 QString *storeId,
938 QString *storeName,
939 QString *entryId,
940 QString *entryName,
941 QString *entryType,
942 QString *data)
943{
944 QStringList list;
945 if (!unescape_stringlist(in, out: &list))
946 return false;
947 if (list.count() != 7)
948 return false;
949 if (list[0] != QLatin1String("qca_def"))
950 return false;
951 *storeId = list[1];
952 *storeName = list[2];
953 *entryId = list[3];
954 *entryName = list[4];
955 *entryType = list[5];
956 *data = list[6];
957 return true;
958}
959
960class DefaultKeyStoreEntry : public KeyStoreEntryContext
961{
962 Q_OBJECT
963public:
964 KeyStoreEntry::Type _type;
965 QString _id, _name, _storeId, _storeName;
966 Certificate _cert;
967 CRL _crl;
968 mutable QString _serialized;
969
970 DefaultKeyStoreEntry(const Certificate &cert, const QString &storeId, const QString &storeName, Provider *p)
971 : KeyStoreEntryContext(p)
972 {
973 _type = KeyStoreEntry::TypeCertificate;
974 _storeId = storeId;
975 _storeName = storeName;
976 _cert = cert;
977 }
978
979 DefaultKeyStoreEntry(const CRL &crl, const QString &storeId, const QString &storeName, Provider *p)
980 : KeyStoreEntryContext(p)
981 {
982 _type = KeyStoreEntry::TypeCRL;
983 _storeId = storeId;
984 _storeName = storeName;
985 _crl = crl;
986 }
987
988 Provider::Context *clone() const override
989 {
990 return new DefaultKeyStoreEntry(*this);
991 }
992
993 KeyStoreEntry::Type type() const override
994 {
995 return _type;
996 }
997
998 QString id() const override
999 {
1000 return _id;
1001 }
1002
1003 QString name() const override
1004 {
1005 return _name;
1006 }
1007
1008 QString storeId() const override
1009 {
1010 return _storeId;
1011 }
1012
1013 QString storeName() const override
1014 {
1015 return _storeName;
1016 }
1017
1018 Certificate certificate() const override
1019 {
1020 return _cert;
1021 }
1022
1023 CRL crl() const override
1024 {
1025 return _crl;
1026 }
1027
1028 QString serialize() const override
1029 {
1030 if (_serialized.isEmpty()) {
1031 QString typestr;
1032 QString datastr;
1033
1034 if (_type == KeyStoreEntry::TypeCertificate) {
1035 typestr = QStringLiteral("cert");
1036 datastr = Base64().arrayToString(a: _cert.toDER());
1037 } else {
1038 typestr = QStringLiteral("crl");
1039 datastr = Base64().arrayToString(a: _crl.toDER());
1040 }
1041
1042 _serialized = entry_serialize(storeId: _storeId, storeName: _storeName, entryId: _id, entryName: _name, entryType: typestr, data: datastr);
1043 }
1044
1045 return _serialized;
1046 }
1047
1048 static DefaultKeyStoreEntry *deserialize(const QString &in, Provider *provider)
1049 {
1050 QString storeId, storeName, id, name, typestr, datastr;
1051
1052 if (entry_deserialize(in, storeId: &storeId, storeName: &storeName, entryId: &id, entryName: &name, entryType: &typestr, data: &datastr)) {
1053 const QByteArray data = Base64().stringToArray(s: datastr).toByteArray();
1054 DefaultKeyStoreEntry *c;
1055
1056 if (typestr == QLatin1String("cert")) {
1057 Certificate cert = Certificate::fromDER(a: data);
1058 if (cert.isNull())
1059 return nullptr;
1060 c = new DefaultKeyStoreEntry(cert, storeId, storeName, provider);
1061 } else if (typestr == QLatin1String("crl")) {
1062 CRL crl = CRL::fromDER(a: data);
1063 if (crl.isNull())
1064 return nullptr;
1065 c = new DefaultKeyStoreEntry(crl, storeId, storeName, provider);
1066 } else
1067 return nullptr;
1068
1069 c->_id = id;
1070 c->_name = name;
1071 c->_serialized = in;
1072 return c;
1073 }
1074 return nullptr;
1075 }
1076
1077 QString simpleId() const
1078 {
1079 if (_type == KeyStoreEntry::TypeCertificate)
1080 return QString::number(qHash(key: _cert.toDER()));
1081 else
1082 return QString::number(qHash(key: _crl.toDER()));
1083 }
1084
1085 QString simpleName() const
1086 {
1087 // use the common name, else orgname
1088 if (_type == KeyStoreEntry::TypeCertificate) {
1089 QString str = _cert.commonName();
1090 if (str.isEmpty())
1091 str = _cert.subjectInfo().value(key: Organization);
1092 return str;
1093 } else
1094 return _crl.issuerInfo().value(key: CommonName);
1095 }
1096};
1097
1098//----------------------------------------------------------------------------
1099// DefaultKeyStoreList
1100//----------------------------------------------------------------------------
1101class DefaultKeyStoreList : public KeyStoreListContext
1102{
1103 Q_OBJECT
1104public:
1105 bool x509_supported;
1106 DefaultShared *shared;
1107
1108 DefaultKeyStoreList(Provider *p, DefaultShared *_shared)
1109 : KeyStoreListContext(p)
1110 , shared(_shared)
1111 {
1112 }
1113
1114 ~DefaultKeyStoreList() override
1115 {
1116 }
1117
1118 Provider::Context *clone() const override
1119 {
1120 return nullptr;
1121 }
1122
1123 void start() override
1124 {
1125 x509_supported = false;
1126
1127 QMetaObject::invokeMethod(obj: this, member: "busyEnd", c: Qt::QueuedConnection);
1128 }
1129
1130 QList<int> keyStores() override
1131 {
1132 if (!x509_supported) {
1133 if (isSupported(features: "cert") && isSupported(features: "crl"))
1134 x509_supported = true;
1135 }
1136
1137 bool have_systemstore = false;
1138#ifndef QCA_NO_SYSTEMSTORE
1139 if (shared->use_system())
1140 have_systemstore = qca_have_systemstore();
1141#endif
1142
1143 QList<int> list;
1144
1145 // system store only shows up if the OS store is available or
1146 // there is a configured store file
1147 if (x509_supported && (have_systemstore || !shared->roots_file().isEmpty()))
1148 list += 0;
1149
1150 return list;
1151 }
1152
1153 KeyStore::Type type(int) const override
1154 {
1155 return KeyStore::System;
1156 }
1157
1158 QString storeId(int) const override
1159 {
1160 return QStringLiteral("qca-default-systemstore");
1161 }
1162
1163 QString name(int) const override
1164 {
1165 return QStringLiteral("System Trusted Certificates");
1166 }
1167
1168 QList<KeyStoreEntry::Type> entryTypes(int) const override
1169 {
1170 QList<KeyStoreEntry::Type> list;
1171 list += KeyStoreEntry::TypeCertificate;
1172 list += KeyStoreEntry::TypeCRL;
1173 return list;
1174 }
1175
1176 QList<KeyStoreEntryContext *> entryList(int) override
1177 {
1178 QList<KeyStoreEntryContext *> out;
1179
1180 QList<Certificate> certs;
1181 QList<CRL> crls;
1182
1183 if (shared->use_system()) {
1184 CertificateCollection col;
1185#ifndef QCA_NO_SYSTEMSTORE
1186 col = qca_get_systemstore(provider: QString());
1187#endif
1188 certs += col.certificates();
1189 crls += col.crls();
1190 }
1191
1192 const QString roots = shared->roots_file();
1193 if (!roots.isEmpty()) {
1194 CertificateCollection col = CertificateCollection::fromFlatTextFile(fileName: roots);
1195 certs += col.certificates();
1196 crls += col.crls();
1197 }
1198
1199#ifdef FRIENDLY_NAMES
1200 const QStringList names = makeFriendlyNames(list: certs);
1201#endif
1202 for (int n = 0; n < certs.count(); ++n) {
1203 DefaultKeyStoreEntry *c = new DefaultKeyStoreEntry(certs[n], storeId(0), name(0), provider());
1204 c->_id = c->simpleId();
1205#ifdef FRIENDLY_NAMES
1206 c->_name = names[n];
1207#else
1208 c->_name = c->simpleName();
1209#endif
1210 out.append(t: c);
1211 }
1212
1213 for (int n = 0; n < crls.count(); ++n) {
1214 DefaultKeyStoreEntry *c = new DefaultKeyStoreEntry(crls[n], storeId(0), name(0), provider());
1215 c->_id = c->simpleId();
1216 c->_name = c->simpleName();
1217 out.append(t: c);
1218 }
1219
1220 return out;
1221 }
1222
1223 KeyStoreEntryContext *entryPassive(const QString &serialized) override
1224 {
1225 return DefaultKeyStoreEntry::deserialize(in: serialized, provider: provider());
1226 }
1227};
1228
1229//----------------------------------------------------------------------------
1230// DefaultProvider
1231//----------------------------------------------------------------------------
1232static bool unescape_config_stringlist(const QString &in, QStringList *_out)
1233{
1234 QStringList out;
1235 const QStringList list = in.split(sep: QLatin1Char(','));
1236 for (int n = 0; n < list.count(); ++n) {
1237 QString str;
1238 if (!unescape_string(in: list[n], out: &str))
1239 return false;
1240 out += str.trimmed();
1241 }
1242 *_out = out;
1243 return true;
1244}
1245
1246class DefaultProvider : public Provider
1247{
1248public:
1249 DefaultShared shared;
1250
1251 void init() override
1252 {
1253 const QDateTime now = QDateTime::currentDateTime();
1254
1255 uint t = now.toSecsSinceEpoch();
1256 if (now.time().msec() > 0)
1257 t /= now.time().msec();
1258 std::srand(seed: t);
1259 }
1260
1261 int version() const override
1262 {
1263 return QCA_VERSION;
1264 }
1265
1266 int qcaVersion() const override
1267 {
1268 return QCA_VERSION;
1269 }
1270
1271 QString name() const override
1272 {
1273 return QStringLiteral("default");
1274 }
1275
1276 QStringList features() const override
1277 {
1278 QStringList list;
1279 list += QStringLiteral("random");
1280 list += QStringLiteral("md5");
1281 list += QStringLiteral("sha1");
1282 list += QStringLiteral("keystorelist");
1283 return list;
1284 }
1285
1286 Provider::Context *createContext(const QString &type) override
1287 {
1288 if (type == QLatin1String("random"))
1289 return new DefaultRandomContext(this);
1290 else if (type == QLatin1String("md5"))
1291 return new DefaultMD5Context(this);
1292 else if (type == QLatin1String("sha1"))
1293 return new DefaultSHA1Context(this);
1294 else if (type == QLatin1String("keystorelist"))
1295 return new DefaultKeyStoreList(this, &shared);
1296 else
1297 return nullptr;
1298 }
1299
1300 QVariantMap defaultConfig() const override
1301 {
1302 QVariantMap config;
1303 config[QStringLiteral("formtype")] = QStringLiteral("http://affinix.com/qca/forms/default#1.0");
1304 config[QStringLiteral("use_system")] = true;
1305 config[QStringLiteral("roots_file")] = QString();
1306 config[QStringLiteral("skip_plugins")] = QString();
1307 config[QStringLiteral("plugin_priorities")] = QString();
1308 return config;
1309 }
1310
1311 void configChanged(const QVariantMap &config) override
1312 {
1313 const bool use_system = config[QStringLiteral("use_system")].toBool();
1314 const QString roots_file = config[QStringLiteral("roots_file")].toString();
1315 const QString skip_plugins_str = config[QStringLiteral("skip_plugins")].toString();
1316 const QString plugin_priorities_str = config[QStringLiteral("plugin_priorities")].toString();
1317
1318 QStringList tmp;
1319
1320 QStringList skip_plugins;
1321 if (unescape_config_stringlist(in: skip_plugins_str, out: &tmp))
1322 skip_plugins = tmp;
1323
1324 QStringList plugin_priorities;
1325 if (unescape_config_stringlist(in: plugin_priorities_str, out: &tmp))
1326 plugin_priorities = tmp;
1327
1328 for (int n = 0; n < plugin_priorities.count(); ++n) {
1329 QString &s = plugin_priorities[n];
1330
1331 // make sure the entry ends with ":number"
1332 int x = s.indexOf(c: QLatin1Char(':'));
1333 bool ok = false;
1334 if (x != -1)
1335#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2)
1336 (void)QStringView(s).mid(pos: x + 1).toInt(ok: &ok);
1337#else
1338 s.midRef(x + 1).toInt(&ok);
1339#endif
1340 if (!ok) {
1341 plugin_priorities.removeAt(i: n);
1342 --n;
1343 }
1344 }
1345
1346 shared.set(use_system, roots_file, skip_plugins, plugin_priorities);
1347 }
1348};
1349
1350Provider *create_default_provider()
1351{
1352 return new DefaultProvider;
1353}
1354
1355QStringList skip_plugins(Provider *defaultProvider)
1356{
1357 DefaultProvider *that = (DefaultProvider *)defaultProvider;
1358 return that->shared.skip_plugins();
1359}
1360
1361QStringList plugin_priorities(Provider *defaultProvider)
1362{
1363 DefaultProvider *that = (DefaultProvider *)defaultProvider;
1364 return that->shared.plugin_priorities();
1365}
1366
1367}
1368
1369#include "qca_default.moc"
1370

source code of qca/src/qca_default.cpp