1 /*
2 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
3 * Copyright (C) 2004-2006 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_cert.h"
23
24 #include "qca_publickey.h"
25 #include "qcaprovider.h"
26
27 #include <QFile>
28 #include <QRegExp>
29 #include <QRegularExpression>
30 #include <QTextStream>
31 #include <QUrl>
32
33 #include <cstdlib>
34
35 namespace QCA {
36
37 Provider::Context *getContext(const QString &type, const QString &provider);
38 Provider::Context *getContext(const QString &type, Provider *p);
39
40 // from qca_publickey.cpp
41 bool stringToFile(const QString &fileName, const QString &content);
42 bool stringFromFile(const QString &fileName, QString *s);
43 bool arrayToFile(const QString &fileName, const QByteArray &content);
44 bool arrayFromFile(const QString &fileName, QByteArray *a);
45 bool ask_passphrase(const QString &fname, void *ptr, SecureArray *answer);
46 ProviderList allProviders();
47 Provider * providerForName(const QString &name);
48 bool use_asker_fallback(ConvertResult r);
49
50 // last 3 arguments must be valid, and chain must be empty
get_pkcs12_der(const QByteArray & der,const QString & fileName,void * ptr,const SecureArray & passphrase,ConvertResult * result,const QString & provider,QString * name,CertificateChain * chain,PrivateKey * key)51 static bool get_pkcs12_der(const QByteArray & der,
52 const QString & fileName,
53 void * ptr,
54 const SecureArray &passphrase,
55 ConvertResult * result,
56 const QString & provider,
57 QString * name,
58 CertificateChain * chain,
59 PrivateKey * key)
60 {
61 QString _name;
62 QList<CertContext *> list;
63 PKeyContext * kc = nullptr;
64
65 PKCS12Context *pix = static_cast<PKCS12Context *>(getContext(QStringLiteral("pkcs12"), provider));
66 ConvertResult r = pix->fromPKCS12(der, passphrase, &_name, &list, &kc);
67
68 // error converting without passphrase? maybe a passphrase is needed
69 if (use_asker_fallback(r) && passphrase.isEmpty()) {
70 SecureArray pass;
71 if (ask_passphrase(fileName, ptr, &pass))
72 r = pix->fromPKCS12(der, pass, &_name, &list, &kc);
73 }
74 delete pix;
75
76 if (result)
77 *result = r;
78
79 if (r == ConvertGood) {
80 *name = _name;
81 for (int n = 0; n < list.count(); ++n) {
82 Certificate cert;
83 cert.change(list[n]);
84 chain->append(cert);
85 }
86 key->change(kc);
87 return true;
88 }
89 return false;
90 }
91
orderedToMap(const CertificateInfoOrdered & info)92 static CertificateInfo orderedToMap(const CertificateInfoOrdered &info)
93 {
94 CertificateInfo out;
95
96 // first, do all but EmailLegacy
97 for (int n = 0; n < info.count(); ++n) {
98 const CertificateInfoPair &i = info[n];
99 if (i.type().known() != EmailLegacy)
100 out.insert(i.type(), i.value());
101 }
102
103 // lastly, apply EmailLegacy
104 for (int n = 0; n < info.count(); ++n) {
105 const CertificateInfoPair &i = info[n];
106 if (i.type().known() == EmailLegacy) {
107 // de-dup
108 const QList<QString> emails = out.values(Email);
109 if (!emails.contains(i.value()))
110 out.insert(Email, i.value());
111 }
112 }
113
114 return out;
115 }
116
moveMapValues(CertificateInfo * from,CertificateInfoOrdered * to,const CertificateInfoType & type)117 static void moveMapValues(CertificateInfo *from, CertificateInfoOrdered *to, const CertificateInfoType &type)
118 {
119 const QList<QString> values = from->values(type);
120 from->remove(type);
121
122 // multimap values are stored in reverse. we'll insert backwards in
123 // order to right them.
124 for (int n = values.count() - 1; n >= 0; --n)
125 to->append(CertificateInfoPair(type, values[n]));
126 }
127
mapToOrdered(const CertificateInfo & info)128 static CertificateInfoOrdered mapToOrdered(const CertificateInfo &info)
129 {
130 CertificateInfo in = info;
131 CertificateInfoOrdered out;
132
133 // have a specific order for some types
134 moveMapValues(&in, &out, CommonName);
135 moveMapValues(&in, &out, Country);
136 moveMapValues(&in, &out, Locality);
137 moveMapValues(&in, &out, State);
138 moveMapValues(&in, &out, Organization);
139 moveMapValues(&in, &out, OrganizationalUnit);
140 moveMapValues(&in, &out, Email);
141 moveMapValues(&in, &out, URI);
142 moveMapValues(&in, &out, DNS);
143 moveMapValues(&in, &out, IPAddress);
144 moveMapValues(&in, &out, XMPP);
145
146 // get remaining types
147 const QList<CertificateInfoType> typesLeft = in.keys();
148
149 // dedup
150 QList<CertificateInfoType> types;
151 for (int n = 0; n < typesLeft.count(); ++n) {
152 if (!types.contains(typesLeft[n]))
153 types += typesLeft[n];
154 }
155
156 // insert the rest of the types in the order we got them (map order)
157 for (int n = 0; n < types.count(); ++n)
158 moveMapValues(&in, &out, types[n]);
159
160 Q_ASSERT(in.isEmpty());
161
162 return out;
163 }
164
165 //----------------------------------------------------------------------------
166 // Global
167 //----------------------------------------------------------------------------
168 static const char CommonName_id[] = "2.5.4.3";
169 static const char Email_id[] = "GeneralName.rfc822Name";
170 static const char EmailLegacy_id[] = "1.2.840.113549.1.9.1";
171 static const char Organization_id[] = "2.5.4.10";
172 static const char OrganizationalUnit_id[] = "2.5.4.11";
173 static const char Locality_id[] = "2.5.4.7";
174 static const char IncorporationLocality_id[] = "1.3.6.1.4.1.311.60.2.1.1";
175 static const char State_id[] = "2.5.4.8";
176 static const char IncorporationState_id[] = "1.3.6.1.4.1.311.60.2.1.2";
177 static const char Country_id[] = "2.5.4.6";
178 static const char IncorporationCountry_id[] = "1.3.6.1.4.1.311.60.2.1.3";
179 static const char URI_id[] = "GeneralName.uniformResourceIdentifier";
180 static const char DNS_id[] = "GeneralName.dNSName";
181 static const char IPAddress_id[] = "GeneralName.iPAddress";
182 static const char XMPP_id[] = "1.3.6.1.5.5.7.8.5";
183
184 static const char DigitalSignature_id[] = "KeyUsage.digitalSignature";
185 static const char NonRepudiation_id[] = "KeyUsage.nonRepudiation";
186 static const char KeyEncipherment_id[] = "KeyUsage.keyEncipherment";
187 static const char DataEncipherment_id[] = "KeyUsage.dataEncipherment";
188 static const char KeyAgreement_id[] = "KeyUsage.keyAgreement";
189 static const char KeyCertificateSign_id[] = "KeyUsage.keyCertSign";
190 static const char CRLSign_id[] = "KeyUsage.crlSign";
191 static const char EncipherOnly_id[] = "KeyUsage.encipherOnly";
192 static const char DecipherOnly_id[] = "KeyUsage.decipherOnly";
193 static const char ServerAuth_id[] = "1.3.6.1.5.5.7.3.1";
194 static const char ClientAuth_id[] = "1.3.6.1.5.5.7.3.2";
195 static const char CodeSigning_id[] = "1.3.6.1.5.5.7.3.3";
196 static const char EmailProtection_id[] = "1.3.6.1.5.5.7.3.4";
197 static const char IPSecEndSystem_id[] = "1.3.6.1.5.5.7.3.5";
198 static const char IPSecTunnel_id[] = "1.3.6.1.5.5.7.3.6";
199 static const char IPSecUser_id[] = "1.3.6.1.5.5.7.3.7";
200 static const char TimeStamping_id[] = "1.3.6.1.5.5.7.3.8";
201 static const char OCSPSigning_id[] = "1.3.6.1.5.5.7.3.9";
202
knownToId(CertificateInfoTypeKnown k)203 static QString knownToId(CertificateInfoTypeKnown k)
204 {
205 const char *out = nullptr;
206 switch (k) {
207 case CommonName:
208 out = CommonName_id;
209 break;
210 case Email:
211 out = Email_id;
212 break;
213 case EmailLegacy:
214 out = EmailLegacy_id;
215 break;
216 case Organization:
217 out = Organization_id;
218 break;
219 case OrganizationalUnit:
220 out = OrganizationalUnit_id;
221 break;
222 case Locality:
223 out = Locality_id;
224 break;
225 case IncorporationLocality:
226 out = IncorporationLocality_id;
227 break;
228 case State:
229 out = State_id;
230 break;
231 case IncorporationState:
232 out = IncorporationState_id;
233 break;
234 case Country:
235 out = Country_id;
236 break;
237 case IncorporationCountry:
238 out = IncorporationCountry_id;
239 break;
240 case URI:
241 out = URI_id;
242 break;
243 case DNS:
244 out = DNS_id;
245 break;
246 case IPAddress:
247 out = IPAddress_id;
248 break;
249 case XMPP:
250 out = XMPP_id;
251 break;
252 }
253 Q_ASSERT(out);
254 if (!out)
255 abort();
256 return QString::fromLatin1(out);
257 }
258
idToKnown(const QString & id)259 static int idToKnown(const QString &id)
260 {
261 if (id == QLatin1String(CommonName_id))
262 return CommonName;
263 else if (id == QLatin1String(Email_id))
264 return Email;
265 else if (id == QLatin1String(EmailLegacy_id))
266 return EmailLegacy;
267 else if (id == QLatin1String(Organization_id))
268 return Organization;
269 else if (id == QLatin1String(OrganizationalUnit_id))
270 return OrganizationalUnit;
271 else if (id == QLatin1String(Locality_id))
272 return Locality;
273 else if (id == QLatin1String(IncorporationLocality_id))
274 return IncorporationLocality;
275 else if (id == QLatin1String(State_id))
276 return State;
277 else if (id == QLatin1String(IncorporationState_id))
278 return IncorporationState;
279 else if (id == QLatin1String(Country_id))
280 return Country;
281 else if (id == QLatin1String(IncorporationCountry_id))
282 return IncorporationCountry;
283 else if (id == QLatin1String(URI_id))
284 return URI;
285 else if (id == QLatin1String(DNS_id))
286 return DNS;
287 else if (id == QLatin1String(IPAddress_id))
288 return IPAddress;
289 else if (id == QLatin1String(XMPP_id))
290 return XMPP;
291 else
292 return -1;
293 }
294
knownToSection(CertificateInfoTypeKnown k)295 static CertificateInfoType::Section knownToSection(CertificateInfoTypeKnown k)
296 {
297 switch (k) {
298 case CommonName:
299 case EmailLegacy:
300 case Organization:
301 case OrganizationalUnit:
302 case Locality:
303 case IncorporationLocality:
304 case State:
305 case IncorporationState:
306 case Country:
307 case IncorporationCountry:
308 return CertificateInfoType::DN;
309 default:
310 break;
311 }
312 return CertificateInfoType::AlternativeName;
313 }
314
knownToShortName(CertificateInfoTypeKnown k)315 static const char *knownToShortName(CertificateInfoTypeKnown k)
316 {
317 switch (k) {
318 case CommonName:
319 return "CN";
320 case Locality:
321 return "L";
322 case State:
323 return "ST";
324 case Organization:
325 return "O";
326 case OrganizationalUnit:
327 return "OU";
328 case Country:
329 return "C";
330 case EmailLegacy:
331 return "emailAddress";
332 default:
333 break;
334 }
335 return nullptr;
336 }
337
constraintKnownToId(ConstraintTypeKnown k)338 static QString constraintKnownToId(ConstraintTypeKnown k)
339 {
340 const char *out = nullptr;
341 switch (k) {
342 case DigitalSignature:
343 out = DigitalSignature_id;
344 break;
345 case NonRepudiation:
346 out = NonRepudiation_id;
347 break;
348 case KeyEncipherment:
349 out = KeyEncipherment_id;
350 break;
351 case DataEncipherment:
352 out = DataEncipherment_id;
353 break;
354 case KeyAgreement:
355 out = KeyAgreement_id;
356 break;
357 case KeyCertificateSign:
358 out = KeyCertificateSign_id;
359 break;
360 case CRLSign:
361 out = CRLSign_id;
362 break;
363 case EncipherOnly:
364 out = EncipherOnly_id;
365 break;
366 case DecipherOnly:
367 out = DecipherOnly_id;
368 break;
369 case ServerAuth:
370 out = ServerAuth_id;
371 break;
372 case ClientAuth:
373 out = ClientAuth_id;
374 break;
375 case CodeSigning:
376 out = CodeSigning_id;
377 break;
378 case EmailProtection:
379 out = EmailProtection_id;
380 break;
381 case IPSecEndSystem:
382 out = IPSecEndSystem_id;
383 break;
384 case IPSecTunnel:
385 out = IPSecTunnel_id;
386 break;
387 case IPSecUser:
388 out = IPSecUser_id;
389 break;
390 case TimeStamping:
391 out = TimeStamping_id;
392 break;
393 case OCSPSigning:
394 out = OCSPSigning_id;
395 break;
396 }
397 Q_ASSERT(out);
398 if (!out)
399 abort();
400 return QString::fromLatin1(out);
401 }
402
constraintIdToKnown(const QString & id)403 static int constraintIdToKnown(const QString &id)
404 {
405 if (id == QLatin1String(DigitalSignature_id))
406 return DigitalSignature;
407 else if (id == QLatin1String(NonRepudiation_id))
408 return NonRepudiation;
409 else if (id == QLatin1String(KeyEncipherment_id))
410 return KeyEncipherment;
411 else if (id == QLatin1String(DataEncipherment_id))
412 return DataEncipherment;
413 else if (id == QLatin1String(KeyAgreement_id))
414 return KeyAgreement;
415 else if (id == QLatin1String(KeyCertificateSign_id))
416 return KeyCertificateSign;
417 else if (id == QLatin1String(CRLSign_id))
418 return CRLSign;
419 else if (id == QLatin1String(EncipherOnly_id))
420 return EncipherOnly;
421 else if (id == QLatin1String(DecipherOnly_id))
422 return DecipherOnly;
423 else if (id == QLatin1String(ServerAuth_id))
424 return ServerAuth;
425 else if (id == QLatin1String(ClientAuth_id))
426 return ClientAuth;
427 else if (id == QLatin1String(CodeSigning_id))
428 return CodeSigning;
429 else if (id == QLatin1String(EmailProtection_id))
430 return EmailProtection;
431 else if (id == QLatin1String(IPSecEndSystem_id))
432 return IPSecEndSystem;
433 else if (id == QLatin1String(IPSecTunnel_id))
434 return IPSecTunnel;
435 else if (id == QLatin1String(IPSecUser_id))
436 return IPSecUser;
437 else if (id == QLatin1String(TimeStamping_id))
438 return TimeStamping;
439 else if (id == QLatin1String(OCSPSigning_id))
440 return OCSPSigning;
441 else
442 return -1;
443 }
444
constraintKnownToSection(ConstraintTypeKnown k)445 static ConstraintType::Section constraintKnownToSection(ConstraintTypeKnown k)
446 {
447 switch (k) {
448 case DigitalSignature:
449 case NonRepudiation:
450 case KeyEncipherment:
451 case DataEncipherment:
452 case KeyAgreement:
453 case KeyCertificateSign:
454 case CRLSign:
455 case EncipherOnly:
456 case DecipherOnly:
457 return ConstraintType::KeyUsage;
458 default:
459 break;
460 }
461 return ConstraintType::ExtendedKeyUsage;
462 }
463
dnLabel(const CertificateInfoType & type)464 static QString dnLabel(const CertificateInfoType &type)
465 {
466 const char *str = knownToShortName(type.known());
467 if (str)
468 return QString::fromLatin1(str);
469
470 const QString id = type.id();
471 // is it an oid?
472 if (id[0].isDigit())
473 return QStringLiteral("OID.") + id;
474
475 return QStringLiteral("qca.") + id;
476 }
477
orderedToDNString(const CertificateInfoOrdered & in)478 QString orderedToDNString(const CertificateInfoOrdered &in)
479 {
480 QStringList parts;
481 foreach (const CertificateInfoPair &i, in) {
482 if (i.type().section() != CertificateInfoType::DN)
483 continue;
484
485 const QString name = dnLabel(i.type());
486 parts += name + QLatin1Char('=') + i.value();
487 }
488 return parts.join(QStringLiteral(", "));
489 }
490
orderedDNOnly(const CertificateInfoOrdered & in)491 CertificateInfoOrdered orderedDNOnly(const CertificateInfoOrdered &in)
492 {
493 CertificateInfoOrdered out;
494 for (int n = 0; n < in.count(); ++n) {
495 if (in[n].type().section() == CertificateInfoType::DN)
496 out += in[n];
497 }
498 return out;
499 }
500
baseCertName(const CertificateInfo & info)501 static QString baseCertName(const CertificateInfo &info)
502 {
503 QString str = info.value(CommonName);
504 if (str.isEmpty()) {
505 str = info.value(Organization);
506 if (str.isEmpty())
507 str = QStringLiteral("Unnamed");
508 }
509 return str;
510 }
511
findSameName(const QString & name,const QStringList & list)512 static QList<int> findSameName(const QString &name, const QStringList &list)
513 {
514 QList<int> out;
515 for (int n = 0; n < list.count(); ++n) {
516 if (list[n] == name)
517 out += n;
518 }
519 return out;
520 }
521
522 static QString
uniqueSubjectValue(const CertificateInfoType & type,const QList<int> & items,const QList<Certificate> & certs,int i)523 uniqueSubjectValue(const CertificateInfoType &type, const QList<int> &items, const QList<Certificate> &certs, int i)
524 {
525 QStringList vals = certs[items[i]].subjectInfo().values(type);
526 if (!vals.isEmpty()) {
527 foreach (int n, items) {
528 if (n == items[i])
529 continue;
530
531 const QStringList other_vals = certs[n].subjectInfo().values(type);
532 for (int k = 0; k < vals.count(); ++k) {
533 if (other_vals.contains(vals[k])) {
534 vals.removeAt(k);
535 break;
536 }
537 }
538
539 if (vals.isEmpty())
540 break;
541 }
542
543 if (!vals.isEmpty())
544 return vals[0];
545 }
546
547 return QString();
548 }
549
uniqueIssuerName(const QList<int> & items,const QList<Certificate> & certs,int i)550 static QString uniqueIssuerName(const QList<int> &items, const QList<Certificate> &certs, int i)
551 {
552 const QString val = baseCertName(certs[items[i]].issuerInfo());
553
554 bool found = false;
555 foreach (int n, items) {
556 if (n == items[i])
557 continue;
558
559 const QString other_val = baseCertName(certs[n].issuerInfo());
560 if (other_val == val) {
561 found = true;
562 break;
563 }
564 }
565
566 if (!found)
567 return val;
568
569 return QString();
570 }
571
constraintToString(const ConstraintType & type)572 static const char *constraintToString(const ConstraintType &type)
573 {
574 switch (type.known()) {
575 case DigitalSignature:
576 return "DigitalSignature";
577 case NonRepudiation:
578 return "NonRepudiation";
579 case KeyEncipherment:
580 return "KeyEncipherment";
581 case DataEncipherment:
582 return "DataEncipherment";
583 case KeyAgreement:
584 return "KeyAgreement";
585 case KeyCertificateSign:
586 return "KeyCertificateSign";
587 case CRLSign:
588 return "CRLSign";
589 case EncipherOnly:
590 return "EncipherOnly";
591 case DecipherOnly:
592 return "DecipherOnly";
593 case ServerAuth:
594 return "ServerAuth";
595 case ClientAuth:
596 return "ClientAuth";
597 case CodeSigning:
598 return "CodeSigning";
599 case EmailProtection:
600 return "EmailProtection";
601 case IPSecEndSystem:
602 return "IPSecEndSystem";
603 case IPSecTunnel:
604 return "IPSecTunnel";
605 case IPSecUser:
606 return "IPSecUser";
607 case TimeStamping:
608 return "TimeStamping";
609 case OCSPSigning:
610 return "OCSPSigning";
611 }
612 return nullptr;
613 }
614
615 static QString
uniqueConstraintValue(const ConstraintType & type,const QList<int> & items,const QList<Certificate> & certs,int i)616 uniqueConstraintValue(const ConstraintType &type, const QList<int> &items, const QList<Certificate> &certs, int i)
617 {
618 if (certs[items[i]].constraints().contains(type)) {
619 bool found = false;
620 foreach (int n, items) {
621 if (n == items[i])
622 continue;
623
624 Constraints other_vals = certs[n].constraints();
625 if (other_vals.contains(type)) {
626 found = true;
627 break;
628 }
629 }
630
631 if (!found)
632 return QString::fromLatin1(constraintToString(type));
633 }
634
635 return QString();
636 }
637
makeUniqueName(const QList<int> & items,const QStringList & list,const QList<Certificate> & certs,int i)638 static QString makeUniqueName(const QList<int> &items, const QStringList &list, const QList<Certificate> &certs, int i)
639 {
640 QString str, name;
641
642 // different organization?
643 str = uniqueSubjectValue(Organization, items, certs, i);
644 if (!str.isEmpty()) {
645 name = list[items[i]] + QStringLiteral(" of ") + str;
646 goto end;
647 }
648
649 // different organizational unit?
650 str = uniqueSubjectValue(OrganizationalUnit, items, certs, i);
651 if (!str.isEmpty()) {
652 name = list[items[i]] + QStringLiteral(" of ") + str;
653 goto end;
654 }
655
656 // different email address?
657 str = uniqueSubjectValue(Email, items, certs, i);
658 if (!str.isEmpty()) {
659 name = list[items[i]] + QStringLiteral(" <") + str + QLatin1Char('>');
660 goto end;
661 }
662
663 // different xmpp addresses?
664 str = uniqueSubjectValue(XMPP, items, certs, i);
665 if (!str.isEmpty()) {
666 name = list[items[i]] + QStringLiteral(" <xmpp:") + str + QLatin1Char('>');
667 goto end;
668 }
669
670 // different issuers?
671 str = uniqueIssuerName(items, certs, i);
672 if (!str.isEmpty()) {
673 name = list[items[i]] + QStringLiteral(" by ") + str;
674 goto end;
675 }
676
677 // different usages?
678
679 // DigitalSignature
680 str = uniqueConstraintValue(DigitalSignature, items, certs, i);
681 if (!str.isEmpty()) {
682 name = list[items[i]] + QStringLiteral(" for ") + str;
683 goto end;
684 }
685
686 // ClientAuth
687 str = uniqueConstraintValue(ClientAuth, items, certs, i);
688 if (!str.isEmpty()) {
689 name = list[items[i]] + QStringLiteral(" for ") + str;
690 goto end;
691 }
692
693 // EmailProtection
694 str = uniqueConstraintValue(EmailProtection, items, certs, i);
695 if (!str.isEmpty()) {
696 name = list[items[i]] + QStringLiteral(" for ") + str;
697 goto end;
698 }
699
700 // DataEncipherment
701 str = uniqueConstraintValue(DataEncipherment, items, certs, i);
702 if (!str.isEmpty()) {
703 name = list[items[i]] + QStringLiteral(" for ") + str;
704 goto end;
705 }
706
707 // EncipherOnly
708 str = uniqueConstraintValue(EncipherOnly, items, certs, i);
709 if (!str.isEmpty()) {
710 name = list[items[i]] + QStringLiteral(" for ") + str;
711 goto end;
712 }
713
714 // DecipherOnly
715 str = uniqueConstraintValue(DecipherOnly, items, certs, i);
716 if (!str.isEmpty()) {
717 name = list[items[i]] + QStringLiteral(" for ") + str;
718 goto end;
719 }
720
721 // if there's nothing easily unique, then do a DN string
722 name = certs[items[i]].subjectInfoOrdered().toString();
723
724 end:
725 return name;
726 }
727
makeFriendlyNames(const QList<Certificate> & list)728 QStringList makeFriendlyNames(const QList<Certificate> &list)
729 {
730 QStringList names;
731
732 // give a base name to all certs first
733 foreach (const Certificate &cert, list)
734 names += baseCertName(cert.subjectInfo());
735
736 // come up with a collision list
737 QList<QList<int>> itemCollisions;
738 foreach (const QString &name, names) {
739 // anyone else using this name?
740 const QList<int> items = findSameName(name, names);
741 if (items.count() > 1) {
742 // don't save duplicate collisions
743 bool haveAlready = false;
744 foreach (const QList<int> &other, itemCollisions) {
745 foreach (int n, items) {
746 if (other.contains(n)) {
747 haveAlready = true;
748 break;
749 }
750 }
751
752 if (haveAlready)
753 break;
754 }
755
756 if (haveAlready)
757 continue;
758
759 itemCollisions += items;
760 }
761 }
762
763 // resolve collisions by providing extra details
764 foreach (const QList<int> &items, itemCollisions) {
765 // printf("%d items are using [%s]\n", items.count(), qPrintable(names[items[0]]));
766
767 for (int n = 0; n < items.count(); ++n) {
768 names[items[n]] = makeUniqueName(items, names, list, n);
769 // printf(" %d: reassigning: [%s]\n", items[n], qPrintable(names[items[n]]));
770 }
771 }
772
773 return names;
774 }
775
776 //----------------------------------------------------------------------------
777 // CertificateInfoType
778 //----------------------------------------------------------------------------
779 class CertificateInfoType::Private : public QSharedData
780 {
781 public:
782 CertificateInfoType::Section section;
783 int known;
784 QString id;
785
Private()786 Private()
787 : section(CertificateInfoType::DN)
788 , known(-1)
789 {
790 }
791 };
792
CertificateInfoType()793 CertificateInfoType::CertificateInfoType()
794 : d(new Private)
795 {
796 }
797
CertificateInfoType(CertificateInfoTypeKnown known)798 CertificateInfoType::CertificateInfoType(CertificateInfoTypeKnown known)
799 : d(new Private)
800 {
801 d->section = knownToSection(known);
802 d->known = known;
803 d->id = knownToId(known); // always valid
804 }
805
CertificateInfoType(const QString & id,Section section)806 CertificateInfoType::CertificateInfoType(const QString &id, Section section)
807 : d(new Private)
808 {
809 d->section = section;
810 d->known = idToKnown(id); // can be -1 for unknown
811 d->id = id;
812 }
813
CertificateInfoType(const CertificateInfoType & from)814 CertificateInfoType::CertificateInfoType(const CertificateInfoType &from)
815 : d(from.d)
816 {
817 }
818
~CertificateInfoType()819 CertificateInfoType::~CertificateInfoType()
820 {
821 }
822
operator =(const CertificateInfoType & from)823 CertificateInfoType &CertificateInfoType::operator=(const CertificateInfoType &from)
824 {
825 d = from.d;
826 return *this;
827 }
828
section() const829 CertificateInfoType::Section CertificateInfoType::section() const
830 {
831 return d->section;
832 }
833
known() const834 CertificateInfoTypeKnown CertificateInfoType::known() const
835 {
836 return (CertificateInfoTypeKnown)d->known;
837 }
838
id() const839 QString CertificateInfoType::id() const
840 {
841 return d->id;
842 }
843
operator <(const CertificateInfoType & other) const844 bool CertificateInfoType::operator<(const CertificateInfoType &other) const
845 {
846 // sort by knowns (in enum order), then by ids (in string order)
847 if (d->known != -1) {
848 if (other.d->known == -1)
849 return true;
850 else if (d->known < other.d->known)
851 return true;
852 else
853 return false;
854 } else {
855 if (other.d->known != -1)
856 return false;
857 else if (d->id < other.d->id)
858 return true;
859 else
860 return false;
861 }
862 }
863
operator ==(const CertificateInfoType & other) const864 bool CertificateInfoType::operator==(const CertificateInfoType &other) const
865 {
866 // are both known types?
867 if (d->known != -1 && other.d->known != -1) {
868 // if so, compare the ints
869 if (d->known != other.d->known)
870 return false;
871 } else {
872 // otherwise, compare the string ids
873 if (d->id != other.d->id)
874 return false;
875 }
876
877 if (d->section != other.d->section)
878 return false;
879
880 return true;
881 }
882
883 //----------------------------------------------------------------------------
884 // CertificateInfoPair
885 //----------------------------------------------------------------------------
886 class CertificateInfoPair::Private : public QSharedData
887 {
888 public:
889 CertificateInfoType type;
890 QString value;
891 };
892
CertificateInfoPair()893 CertificateInfoPair::CertificateInfoPair()
894 : d(new Private)
895 {
896 }
897
CertificateInfoPair(const CertificateInfoType & type,const QString & value)898 CertificateInfoPair::CertificateInfoPair(const CertificateInfoType &type, const QString &value)
899 : d(new Private)
900 {
901 d->type = type;
902 d->value = value;
903 }
904
CertificateInfoPair(const CertificateInfoPair & from)905 CertificateInfoPair::CertificateInfoPair(const CertificateInfoPair &from)
906 : d(from.d)
907 {
908 }
909
~CertificateInfoPair()910 CertificateInfoPair::~CertificateInfoPair()
911 {
912 }
913
operator =(const CertificateInfoPair & from)914 CertificateInfoPair &CertificateInfoPair::operator=(const CertificateInfoPair &from)
915 {
916 d = from.d;
917 return *this;
918 }
919
type() const920 CertificateInfoType CertificateInfoPair::type() const
921 {
922 return d->type;
923 }
924
value() const925 QString CertificateInfoPair::value() const
926 {
927 return d->value;
928 }
929
operator ==(const CertificateInfoPair & other) const930 bool CertificateInfoPair::operator==(const CertificateInfoPair &other) const
931 {
932 if (d->type == other.d->type && d->value == other.d->value)
933 return true;
934 return false;
935 }
936
937 //----------------------------------------------------------------------------
938 // ConstraintType
939 //----------------------------------------------------------------------------
940 class ConstraintType::Private : public QSharedData
941 {
942 public:
943 ConstraintType::Section section;
944 int known;
945 QString id;
946
Private()947 Private()
948 : section(ConstraintType::KeyUsage)
949 , known(-1)
950 {
951 }
952 };
953
ConstraintType()954 ConstraintType::ConstraintType()
955 : d(new Private)
956 {
957 }
958
ConstraintType(ConstraintTypeKnown known)959 ConstraintType::ConstraintType(ConstraintTypeKnown known)
960 : d(new Private)
961 {
962 d->section = constraintKnownToSection(known);
963 d->known = known;
964 d->id = constraintKnownToId(known); // always valid
965 }
966
ConstraintType(const QString & id,Section section)967 ConstraintType::ConstraintType(const QString &id, Section section)
968 : d(new Private)
969 {
970 d->section = section;
971 d->known = constraintIdToKnown(id); // can be -1 for unknown
972 d->id = id;
973 }
974
ConstraintType(const ConstraintType & from)975 ConstraintType::ConstraintType(const ConstraintType &from)
976 : d(from.d)
977 {
978 }
979
~ConstraintType()980 ConstraintType::~ConstraintType()
981 {
982 }
983
operator =(const ConstraintType & from)984 ConstraintType &ConstraintType::operator=(const ConstraintType &from)
985 {
986 d = from.d;
987 return *this;
988 }
989
section() const990 ConstraintType::Section ConstraintType::section() const
991 {
992 return d->section;
993 }
994
known() const995 ConstraintTypeKnown ConstraintType::known() const
996 {
997 return (ConstraintTypeKnown)d->known;
998 }
999
id() const1000 QString ConstraintType::id() const
1001 {
1002 return d->id;
1003 }
1004
operator <(const ConstraintType & other) const1005 bool ConstraintType::operator<(const ConstraintType &other) const
1006 {
1007 // sort by knowns (in enum order), then by ids (in string order)
1008 if (d->known != -1) {
1009 if (other.d->known == -1)
1010 return true;
1011 else if (d->known < other.d->known)
1012 return true;
1013 else
1014 return false;
1015 } else {
1016 if (other.d->known != -1)
1017 return false;
1018 else if (d->id < other.d->id)
1019 return true;
1020 else
1021 return false;
1022 }
1023 }
1024
operator ==(const ConstraintType & other) const1025 bool ConstraintType::operator==(const ConstraintType &other) const
1026 {
1027 // are both known types?
1028 if (d->known != -1 && other.d->known != -1) {
1029 // if so, compare the ints
1030 if (d->known != other.d->known)
1031 return false;
1032 } else {
1033 // otherwise, compare the string ids
1034 if (d->id != other.d->id)
1035 return false;
1036 }
1037
1038 if (d->section != other.d->section)
1039 return false;
1040
1041 return true;
1042 }
1043
1044 //----------------------------------------------------------------------------
1045 // CertificateOptions
1046 //----------------------------------------------------------------------------
1047 class CertificateOptions::Private
1048 {
1049 public:
1050 CertificateRequestFormat format;
1051
1052 QString challenge;
1053 CertificateInfoOrdered info;
1054 CertificateInfo infoMap;
1055 Constraints constraints;
1056 QStringList policies;
1057 QStringList crlLocations, issuerLocations, ocspLocations;
1058 bool isCA;
1059 int pathLimit;
1060 BigInteger serial;
1061 QDateTime start, end;
1062
Private()1063 Private()
1064 : isCA(false)
1065 , pathLimit(0)
1066 {
1067 }
1068 };
1069
CertificateOptions(CertificateRequestFormat f)1070 CertificateOptions::CertificateOptions(CertificateRequestFormat f)
1071 {
1072 d = new Private;
1073 d->format = f;
1074 }
1075
CertificateOptions(const CertificateOptions & from)1076 CertificateOptions::CertificateOptions(const CertificateOptions &from)
1077 {
1078 d = new Private(*from.d);
1079 }
1080
~CertificateOptions()1081 CertificateOptions::~CertificateOptions()
1082 {
1083 delete d;
1084 }
1085
operator =(const CertificateOptions & from)1086 CertificateOptions &CertificateOptions::operator=(const CertificateOptions &from)
1087 {
1088 *d = *from.d;
1089 return *this;
1090 }
1091
format() const1092 CertificateRequestFormat CertificateOptions::format() const
1093 {
1094 return d->format;
1095 }
1096
setFormat(CertificateRequestFormat f)1097 void CertificateOptions::setFormat(CertificateRequestFormat f)
1098 {
1099 d->format = f;
1100 }
1101
isValid() const1102 bool CertificateOptions::isValid() const
1103 {
1104 // logic from Botan
1105 if (d->infoMap.value(CommonName).isEmpty() || d->infoMap.value(Country).isEmpty())
1106 return false;
1107 if (d->infoMap.value(Country).length() != 2)
1108 return false;
1109 if (d->start >= d->end)
1110 return false;
1111 return true;
1112 }
1113
challenge() const1114 QString CertificateOptions::challenge() const
1115 {
1116 return d->challenge;
1117 }
1118
info() const1119 CertificateInfo CertificateOptions::info() const
1120 {
1121 return d->infoMap;
1122 }
1123
infoOrdered() const1124 CertificateInfoOrdered CertificateOptions::infoOrdered() const
1125 {
1126 return d->info;
1127 }
1128
constraints() const1129 Constraints CertificateOptions::constraints() const
1130 {
1131 return d->constraints;
1132 }
1133
policies() const1134 QStringList CertificateOptions::policies() const
1135 {
1136 return d->policies;
1137 }
1138
crlLocations() const1139 QStringList CertificateOptions::crlLocations() const
1140 {
1141 return d->crlLocations;
1142 }
1143
issuerLocations() const1144 QStringList CertificateOptions::issuerLocations() const
1145 {
1146 return d->issuerLocations;
1147 }
1148
ocspLocations() const1149 QStringList CertificateOptions::ocspLocations() const
1150 {
1151 return d->ocspLocations;
1152 }
1153
isCA() const1154 bool CertificateOptions::isCA() const
1155 {
1156 return d->isCA;
1157 }
1158
pathLimit() const1159 int CertificateOptions::pathLimit() const
1160 {
1161 return d->pathLimit;
1162 }
1163
serialNumber() const1164 BigInteger CertificateOptions::serialNumber() const
1165 {
1166 return d->serial;
1167 }
1168
notValidBefore() const1169 QDateTime CertificateOptions::notValidBefore() const
1170 {
1171 return d->start;
1172 }
1173
notValidAfter() const1174 QDateTime CertificateOptions::notValidAfter() const
1175 {
1176 return d->end;
1177 }
1178
setChallenge(const QString & s)1179 void CertificateOptions::setChallenge(const QString &s)
1180 {
1181 d->challenge = s;
1182 }
1183
setInfo(const CertificateInfo & info)1184 void CertificateOptions::setInfo(const CertificateInfo &info)
1185 {
1186 d->info = mapToOrdered(info);
1187 d->infoMap = info;
1188 }
1189
setInfoOrdered(const CertificateInfoOrdered & info)1190 void CertificateOptions::setInfoOrdered(const CertificateInfoOrdered &info)
1191 {
1192 d->info = info;
1193 d->infoMap = orderedToMap(info);
1194 }
1195
setConstraints(const Constraints & constraints)1196 void CertificateOptions::setConstraints(const Constraints &constraints)
1197 {
1198 d->constraints = constraints;
1199 }
1200
setPolicies(const QStringList & policies)1201 void CertificateOptions::setPolicies(const QStringList &policies)
1202 {
1203 d->policies = policies;
1204 }
1205
setCRLLocations(const QStringList & locations)1206 void CertificateOptions::setCRLLocations(const QStringList &locations)
1207 {
1208 d->crlLocations = locations;
1209 }
1210
setIssuerLocations(const QStringList & locations)1211 void CertificateOptions::setIssuerLocations(const QStringList &locations)
1212 {
1213 d->issuerLocations = locations;
1214 }
1215
setOCSPLocations(const QStringList & locations)1216 void CertificateOptions::setOCSPLocations(const QStringList &locations)
1217 {
1218 d->ocspLocations = locations;
1219 }
1220
setAsCA(int pathLimit)1221 void CertificateOptions::setAsCA(int pathLimit)
1222 {
1223 d->isCA = true;
1224 d->pathLimit = pathLimit;
1225 }
1226
setAsUser()1227 void CertificateOptions::setAsUser()
1228 {
1229 d->isCA = false;
1230 d->pathLimit = 0;
1231 }
1232
setSerialNumber(const BigInteger & i)1233 void CertificateOptions::setSerialNumber(const BigInteger &i)
1234 {
1235 d->serial = i;
1236 }
1237
setValidityPeriod(const QDateTime & start,const QDateTime & end)1238 void CertificateOptions::setValidityPeriod(const QDateTime &start, const QDateTime &end)
1239 {
1240 d->start = start;
1241 d->end = end;
1242 }
1243
1244 //----------------------------------------------------------------------------
1245 // Certificate
1246 //----------------------------------------------------------------------------
1247 // ip address string to binary (msb), adapted from jdns (adapted from qt)
1248 // return: size 4 = ipv4, size 16 = ipv6, size 0 = error
ipaddr_str2bin(const QString & str)1249 static QByteArray ipaddr_str2bin(const QString &str)
1250 {
1251 // ipv6
1252 if (str.contains(QLatin1Char(':'))) {
1253 const QStringList parts = str.split(QLatin1Char(':'), Qt::KeepEmptyParts);
1254 if (parts.count() < 3 || parts.count() > 8)
1255 return QByteArray();
1256
1257 QByteArray ipv6(16, 0);
1258 int at = 16;
1259 int fill = 9 - parts.count();
1260 for (int n = parts.count() - 1; n >= 0; --n) {
1261 if (at <= 0)
1262 return QByteArray();
1263
1264 if (parts[n].isEmpty()) {
1265 if (n == parts.count() - 1) {
1266 if (!parts[n - 1].isEmpty())
1267 return QByteArray();
1268 ipv6[--at] = 0;
1269 ipv6[--at] = 0;
1270 } else if (n == 0) {
1271 if (!parts[n + 1].isEmpty())
1272 return QByteArray();
1273 ipv6[--at] = 0;
1274 ipv6[--at] = 0;
1275 } else {
1276 for (int i = 0; i < fill; ++i) {
1277 if (at <= 0)
1278 return QByteArray();
1279 ipv6[--at] = 0;
1280 ipv6[--at] = 0;
1281 }
1282 }
1283 } else {
1284 if (parts[n].indexOf(QLatin1Char('.')) == -1) {
1285 bool ok;
1286 int x = parts[n].toInt(&ok, 16);
1287 if (!ok || x < 0 || x > 0xffff)
1288 return QByteArray();
1289 ipv6[--at] = x & 0xff;
1290 ipv6[--at] = (x >> 8) & 0xff;
1291 } else {
1292 if (n != parts.count() - 1)
1293 return QByteArray();
1294
1295 const QByteArray buf = ipaddr_str2bin(parts[n]);
1296 if (buf.isEmpty())
1297 return QByteArray();
1298
1299 ipv6[--at] = buf[3];
1300 ipv6[--at] = buf[2];
1301 ipv6[--at] = buf[1];
1302 ipv6[--at] = buf[0];
1303 --fill;
1304 }
1305 }
1306 }
1307
1308 return ipv6;
1309 } else if (str.contains(QLatin1Char('.'))) {
1310 const QStringList parts = str.split(QLatin1Char('.'), Qt::KeepEmptyParts);
1311 if (parts.count() != 4)
1312 return QByteArray();
1313
1314 QByteArray out(4, 0);
1315 for (int n = 0; n < 4; ++n) {
1316 bool ok;
1317 int x = parts[n].toInt(&ok);
1318 if (!ok || x < 0 || x > 0xff)
1319 return QByteArray();
1320 out[n] = (unsigned char)x;
1321 }
1322 return out;
1323 } else
1324 return QByteArray();
1325 }
1326
1327 // acedomain must be all lowercase, with no trailing dot or wildcards
cert_match_domain(const QString & certname,const QString & acedomain)1328 static bool cert_match_domain(const QString &certname, const QString &acedomain)
1329 {
1330 // KSSL strips start/end whitespace, even though such whitespace is
1331 // probably not legal anyway. (compat)
1332 QString name = certname.trimmed();
1333
1334 // KSSL strips trailing dot, even though the dot is probably not
1335 // legal anyway. (compat)
1336 if (name.length() > 0 && name[name.length() - 1] == QLatin1Char('.'))
1337 name.truncate(name.length() - 1);
1338
1339 // after our compatibility modifications, make sure the name isn't
1340 // empty.
1341 if (name.isEmpty())
1342 return false;
1343
1344 // lowercase, for later performing case insensitive matching
1345 name = name.toLower();
1346
1347 // ensure the cert field contains valid characters only
1348 if (QRegularExpression(QStringLiteral("[^a-z0-9\\.\\*\\-]")).match(name).hasMatch())
1349 return false;
1350
1351 // hack into parts, and require at least 1 part
1352 const QStringList parts_name = name.split(QLatin1Char('.'), Qt::KeepEmptyParts);
1353 if (parts_name.isEmpty())
1354 return false;
1355
1356 // KSSL checks to make sure the last two parts don't contain
1357 // wildcards. I don't know where it is written that this
1358 // should be done, but for compat sake we'll do it.
1359 if (parts_name[parts_name.count() - 1].contains(QLatin1Char('*')))
1360 return false;
1361 if (parts_name.count() >= 2 && parts_name[parts_name.count() - 2].contains(QLatin1Char('*')))
1362 return false;
1363
1364 const QStringList parts_compare = acedomain.split(QLatin1Char('.'), Qt::KeepEmptyParts);
1365 if (parts_compare.isEmpty())
1366 return false;
1367
1368 // don't allow empty parts
1369 foreach (const QString &s, parts_name) {
1370 if (s.isEmpty())
1371 return false;
1372 }
1373 foreach (const QString &s, parts_compare) {
1374 if (s.isEmpty())
1375 return false;
1376 }
1377
1378 // RFC2818: "Names may contain the wildcard character * which is
1379 // considered to match any single domain name component or
1380 // component fragment. E.g., *.a.com matches foo.a.com but not
1381 // bar.foo.a.com. f*.com matches foo.com but not bar.com."
1382 //
1383 // This means that for the domain to match it must have the
1384 // same number of components, wildcards or not. If there are
1385 // wildcards, their scope must only be within the component
1386 // they reside in.
1387 //
1388 // First, make sure the number of parts is equal.
1389 if (parts_name.count() != parts_compare.count())
1390 return false;
1391
1392 // Now compare each part
1393 for (int n = 0; n < parts_name.count(); ++n) {
1394 const QString &p1 = parts_name[n];
1395 const QString &p2 = parts_compare[n];
1396
1397 if (!QRegExp(p1, Qt::CaseSensitive, QRegExp::Wildcard).exactMatch(p2))
1398 return false;
1399 }
1400
1401 return true;
1402 }
1403
1404 // ipaddress must be an ipv4 or ipv6 address in binary format
cert_match_ipaddress(const QString & certname,const QByteArray & ipaddress)1405 static bool cert_match_ipaddress(const QString &certname, const QByteArray &ipaddress)
1406 {
1407 // KSSL strips start/end whitespace, even though such whitespace is
1408 // probably not legal anyway. (compat)
1409 QString name = certname.trimmed();
1410
1411 // KSSL accepts IPv6 in brackets, which is usually done for URIs, but
1412 // IMO sounds very strange for a certificate. We'll follow this
1413 // behavior anyway. (compat)
1414 if (name.length() >= 2 && name[0] == QLatin1Char('[') && name[name.length() - 1] == QLatin1Char(']'))
1415 name = name.mid(1, name.length() - 2); // chop off brackets
1416
1417 // after our compatibility modifications, make sure the name isn't
1418 // empty.
1419 if (name.isEmpty())
1420 return false;
1421
1422 // convert to binary form
1423 const QByteArray addr = ipaddr_str2bin(name);
1424 if (addr.isEmpty())
1425 return false;
1426
1427 // not the same?
1428 if (addr != ipaddress)
1429 return false;
1430
1431 return true;
1432 }
1433
1434 class Certificate::Private : public QSharedData
1435 {
1436 public:
1437 CertificateInfo subjectInfoMap, issuerInfoMap;
1438
update(CertContext * c)1439 void update(CertContext *c)
1440 {
1441 if (c) {
1442 subjectInfoMap = orderedToMap(c->props()->subject);
1443 issuerInfoMap = orderedToMap(c->props()->issuer);
1444 } else {
1445 subjectInfoMap = CertificateInfo();
1446 issuerInfoMap = CertificateInfo();
1447 }
1448 }
1449 };
1450
Certificate()1451 Certificate::Certificate()
1452 : d(new Private)
1453 {
1454 }
1455
Certificate(const QString & fileName)1456 Certificate::Certificate(const QString &fileName)
1457 : d(new Private)
1458 {
1459 *this = fromPEMFile(fileName, nullptr, QString());
1460 }
1461
Certificate(const CertificateOptions & opts,const PrivateKey & key,const QString & provider)1462 Certificate::Certificate(const CertificateOptions &opts, const PrivateKey &key, const QString &provider)
1463 : d(new Private)
1464 {
1465 CertContext *c = static_cast<CertContext *>(getContext(QStringLiteral("cert"), provider));
1466 if (c->createSelfSigned(opts, *(static_cast<const PKeyContext *>(key.context()))))
1467 change(c);
1468 else
1469 delete c;
1470 }
1471
Certificate(const Certificate & from)1472 Certificate::Certificate(const Certificate &from)
1473 : Algorithm(from)
1474 , d(from.d)
1475 {
1476 }
1477
~Certificate()1478 Certificate::~Certificate()
1479 {
1480 }
1481
operator =(const Certificate & from)1482 Certificate &Certificate::operator=(const Certificate &from)
1483 {
1484 Algorithm::operator=(from);
1485 d = from.d;
1486 return *this;
1487 }
1488
isNull() const1489 bool Certificate::isNull() const
1490 {
1491 return (!context() ? true : false);
1492 }
1493
notValidBefore() const1494 QDateTime Certificate::notValidBefore() const
1495 {
1496 return static_cast<const CertContext *>(context())->props()->start;
1497 }
1498
notValidAfter() const1499 QDateTime Certificate::notValidAfter() const
1500 {
1501 return static_cast<const CertContext *>(context())->props()->end;
1502 }
1503
subjectInfo() const1504 CertificateInfo Certificate::subjectInfo() const
1505 {
1506 return d->subjectInfoMap;
1507 }
1508
subjectInfoOrdered() const1509 CertificateInfoOrdered Certificate::subjectInfoOrdered() const
1510 {
1511 return static_cast<const CertContext *>(context())->props()->subject;
1512 }
1513
issuerInfo() const1514 CertificateInfo Certificate::issuerInfo() const
1515 {
1516 return d->issuerInfoMap;
1517 }
1518
issuerInfoOrdered() const1519 CertificateInfoOrdered Certificate::issuerInfoOrdered() const
1520 {
1521 return static_cast<const CertContext *>(context())->props()->issuer;
1522 }
1523
constraints() const1524 Constraints Certificate::constraints() const
1525 {
1526 return static_cast<const CertContext *>(context())->props()->constraints;
1527 }
1528
policies() const1529 QStringList Certificate::policies() const
1530 {
1531 return static_cast<const CertContext *>(context())->props()->policies;
1532 }
1533
crlLocations() const1534 QStringList Certificate::crlLocations() const
1535 {
1536 return static_cast<const CertContext *>(context())->props()->crlLocations;
1537 }
1538
issuerLocations() const1539 QStringList Certificate::issuerLocations() const
1540 {
1541 return static_cast<const CertContext *>(context())->props()->issuerLocations;
1542 }
1543
ocspLocations() const1544 QStringList Certificate::ocspLocations() const
1545 {
1546 return static_cast<const CertContext *>(context())->props()->ocspLocations;
1547 }
1548
commonName() const1549 QString Certificate::commonName() const
1550 {
1551 return d->subjectInfoMap.value(CommonName);
1552 }
1553
serialNumber() const1554 BigInteger Certificate::serialNumber() const
1555 {
1556 return static_cast<const CertContext *>(context())->props()->serial;
1557 }
1558
subjectPublicKey() const1559 PublicKey Certificate::subjectPublicKey() const
1560 {
1561 PKeyContext *c = static_cast<const CertContext *>(context())->subjectPublicKey();
1562 PublicKey key;
1563 key.change(c);
1564 return key;
1565 }
1566
isCA() const1567 bool Certificate::isCA() const
1568 {
1569 return static_cast<const CertContext *>(context())->props()->isCA;
1570 }
1571
isSelfSigned() const1572 bool Certificate::isSelfSigned() const
1573 {
1574 return static_cast<const CertContext *>(context())->props()->isSelfSigned;
1575 }
1576
isIssuerOf(const Certificate & other) const1577 bool Certificate::isIssuerOf(const Certificate &other) const
1578 {
1579 const CertContext *cc = static_cast<const CertContext *>(other.context());
1580 return static_cast<const CertContext *>(context())->isIssuerOf(cc);
1581 }
1582
pathLimit() const1583 int Certificate::pathLimit() const
1584 {
1585 return static_cast<const CertContext *>(context())->props()->pathLimit;
1586 }
1587
signatureAlgorithm() const1588 SignatureAlgorithm Certificate::signatureAlgorithm() const
1589 {
1590 return static_cast<const CertContext *>(context())->props()->sigalgo;
1591 }
1592
subjectKeyId() const1593 QByteArray Certificate::subjectKeyId() const
1594 {
1595 return static_cast<const CertContext *>(context())->props()->subjectId;
1596 }
1597
issuerKeyId() const1598 QByteArray Certificate::issuerKeyId() const
1599 {
1600 return static_cast<const CertContext *>(context())->props()->issuerId;
1601 }
1602
validate(const CertificateCollection & trusted,const CertificateCollection & untrusted,UsageMode u,ValidateFlags vf) const1603 Validity Certificate::validate(const CertificateCollection &trusted,
1604 const CertificateCollection &untrusted,
1605 UsageMode u,
1606 ValidateFlags vf) const
1607 {
1608 const QList<Certificate> issuers = trusted.certificates() + untrusted.certificates();
1609 CertificateChain chain;
1610 chain += *this;
1611 Validity result;
1612 chain = chain.complete(issuers, &result);
1613 if (result != ValidityGood)
1614 return result;
1615 return chain.validate(trusted, untrusted.crls(), u, vf);
1616 }
1617
toDER() const1618 QByteArray Certificate::toDER() const
1619 {
1620 return static_cast<const CertContext *>(context())->toDER();
1621 }
1622
toPEM() const1623 QString Certificate::toPEM() const
1624 {
1625 return static_cast<const CertContext *>(context())->toPEM();
1626 }
1627
toPEMFile(const QString & fileName) const1628 bool Certificate::toPEMFile(const QString &fileName) const
1629 {
1630 return stringToFile(fileName, toPEM());
1631 }
1632
fromDER(const QByteArray & a,ConvertResult * result,const QString & provider)1633 Certificate Certificate::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider)
1634 {
1635 Certificate c;
1636 CertContext * cc = static_cast<CertContext *>(getContext(QStringLiteral("cert"), provider));
1637 ConvertResult r = cc->fromDER(a);
1638 if (result)
1639 *result = r;
1640 if (r == ConvertGood)
1641 c.change(cc);
1642 else
1643 delete cc;
1644 return c;
1645 }
1646
fromPEM(const QString & s,ConvertResult * result,const QString & provider)1647 Certificate Certificate::fromPEM(const QString &s, ConvertResult *result, const QString &provider)
1648 {
1649 Certificate c;
1650 CertContext * cc = static_cast<CertContext *>(getContext(QStringLiteral("cert"), provider));
1651 ConvertResult r = cc->fromPEM(s);
1652 if (result)
1653 *result = r;
1654 if (r == ConvertGood)
1655 c.change(cc);
1656 else
1657 delete cc;
1658 return c;
1659 }
1660
fromPEMFile(const QString & fileName,ConvertResult * result,const QString & provider)1661 Certificate Certificate::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider)
1662 {
1663 QString pem;
1664 if (!stringFromFile(fileName, &pem)) {
1665 if (result)
1666 *result = ErrorFile;
1667 return Certificate();
1668 }
1669 return fromPEM(pem, result, provider);
1670 }
1671
1672 // check for ip addresses in iPAddress, dNSName, then commonName
1673 // for all else, check in dNSName, then commonName
matchesHostName(const QString & host) const1674 bool Certificate::matchesHostName(const QString &host) const
1675 {
1676 const QByteArray ipaddr = ipaddr_str2bin(host);
1677 if (!ipaddr.isEmpty()) // ip address
1678 {
1679 // check iPAddress, dNSName, commonName
1680 const CertificateInfoOrdered subjectInfo = subjectInfoOrdered();
1681 for (const CertificateInfoPair &p : subjectInfo) {
1682 const CertificateInfoType type = p.type();
1683 if (type == IPAddress || type == DNS || type == CommonName) {
1684 if (cert_match_ipaddress(p.value(), ipaddr))
1685 return true;
1686 }
1687 }
1688 } else // domain
1689 {
1690 // lowercase
1691 QString name = host.toLower();
1692
1693 // ACE
1694 name = QString::fromLatin1(QUrl::toAce(name));
1695
1696 // don't allow wildcards in the comparison host
1697 if (name.contains(QLatin1Char('*')))
1698 return false;
1699
1700 // strip out trailing dot
1701 if (name.length() > 0 && name[name.length() - 1] == QLatin1Char('.'))
1702 name.truncate(name.length() - 1);
1703
1704 // make sure the name is not empty after our modifications
1705 if (name.isEmpty())
1706 return false;
1707
1708 // check dNSName, commonName
1709 const CertificateInfoOrdered subjectInfo = subjectInfoOrdered();
1710 for (const CertificateInfoPair &p : subjectInfo) {
1711 const CertificateInfoType type = p.type();
1712 if (type == DNS || type == CommonName) {
1713 if (cert_match_domain(p.value(), name))
1714 return true;
1715 }
1716 }
1717 }
1718
1719 return false;
1720 }
1721
operator ==(const Certificate & otherCert) const1722 bool Certificate::operator==(const Certificate &otherCert) const
1723 {
1724 if (isNull()) {
1725 if (otherCert.isNull())
1726 return true;
1727 else
1728 return false;
1729 } else if (otherCert.isNull())
1730 return false;
1731
1732 const CertContext *other = static_cast<const CertContext *>(otherCert.context());
1733 return static_cast<const CertContext *>(context())->compare(other);
1734 }
1735
change(CertContext * c)1736 void Certificate::change(CertContext *c)
1737 {
1738 Algorithm::change(c);
1739 d->update(static_cast<CertContext *>(context()));
1740 }
1741
chain_validate(const CertificateChain & chain,const CertificateCollection & trusted,const QList<CRL> & untrusted_crls,UsageMode u,ValidateFlags vf) const1742 Validity Certificate::chain_validate(const CertificateChain & chain,
1743 const CertificateCollection &trusted,
1744 const QList<CRL> & untrusted_crls,
1745 UsageMode u,
1746 ValidateFlags vf) const
1747 {
1748 QList<CertContext *> chain_list;
1749 QList<CertContext *> trusted_list;
1750 QList<CRLContext *> crl_list;
1751
1752 QList<Certificate> chain_certs = chain;
1753 QList<Certificate> trusted_certs = trusted.certificates();
1754 QList<CRL> crls = trusted.crls() + untrusted_crls;
1755
1756 for (int n = 0; n < chain_certs.count(); ++n) {
1757 CertContext *c = static_cast<CertContext *>(chain_certs[n].context());
1758 chain_list += c;
1759 }
1760 for (int n = 0; n < trusted_certs.count(); ++n) {
1761 CertContext *c = static_cast<CertContext *>(trusted_certs[n].context());
1762 trusted_list += c;
1763 }
1764 for (int n = 0; n < crls.count(); ++n) {
1765 CRLContext *c = static_cast<CRLContext *>(crls[n].context());
1766 crl_list += c;
1767 }
1768
1769 return static_cast<const CertContext *>(context())->validate_chain(chain_list, trusted_list, crl_list, u, vf);
1770 }
1771
1772 CertificateChain
chain_complete(const CertificateChain & chain,const QList<Certificate> & issuers,Validity * result) const1773 Certificate::chain_complete(const CertificateChain &chain, const QList<Certificate> &issuers, Validity *result) const
1774 {
1775 CertificateChain out;
1776 QList<Certificate> pool = issuers + chain.mid(1);
1777 out += chain.first();
1778 if (result)
1779 *result = ValidityGood;
1780 while (!out.last().isSelfSigned()) {
1781 // try to get next in chain
1782 int at = -1;
1783 for (int n = 0; n < pool.count(); ++n) {
1784 // QString str = QString("[%1] issued by [%2] ? ").arg(out.last().commonName()).arg(pool[n].commonName());
1785 if (pool[n].isIssuerOf(out.last())) {
1786 // printf("%s yes\n", qPrintable(str));
1787 at = n;
1788 break;
1789 }
1790 // printf("%s no\n", qPrintable(str));
1791 }
1792 if (at == -1) {
1793 if (result)
1794 *result = ErrorInvalidCA;
1795 break;
1796 }
1797
1798 // take it out of the pool
1799 Certificate next = pool.takeAt(at);
1800
1801 // make sure it isn't in the chain already (avoid loops)
1802 if (out.contains(next))
1803 break;
1804
1805 // append to the chain
1806 out += next;
1807 }
1808 return out;
1809 }
1810
1811 //----------------------------------------------------------------------------
1812 // CertificateRequest
1813 //----------------------------------------------------------------------------
1814 class CertificateRequest::Private : public QSharedData
1815 {
1816 public:
1817 CertificateInfo subjectInfoMap;
1818
update(CSRContext * c)1819 void update(CSRContext *c)
1820 {
1821 if (c)
1822 subjectInfoMap = orderedToMap(c->props()->subject);
1823 else
1824 subjectInfoMap = CertificateInfo();
1825 }
1826 };
1827
CertificateRequest()1828 CertificateRequest::CertificateRequest()
1829 : d(new Private)
1830 {
1831 }
1832
CertificateRequest(const QString & fileName)1833 CertificateRequest::CertificateRequest(const QString &fileName)
1834 : d(new Private)
1835 {
1836 *this = fromPEMFile(fileName, nullptr, QString());
1837 }
1838
CertificateRequest(const CertificateOptions & opts,const PrivateKey & key,const QString & provider)1839 CertificateRequest::CertificateRequest(const CertificateOptions &opts, const PrivateKey &key, const QString &provider)
1840 : d(new Private)
1841 {
1842 CSRContext *c = static_cast<CSRContext *>(getContext(QStringLiteral("csr"), provider));
1843 if (c->createRequest(opts, *(static_cast<const PKeyContext *>(key.context()))))
1844 change(c);
1845 else
1846 delete c;
1847 }
1848
CertificateRequest(const CertificateRequest & from)1849 CertificateRequest::CertificateRequest(const CertificateRequest &from)
1850 : Algorithm(from)
1851 , d(from.d)
1852 {
1853 }
1854
~CertificateRequest()1855 CertificateRequest::~CertificateRequest()
1856 {
1857 }
1858
operator =(const CertificateRequest & from)1859 CertificateRequest &CertificateRequest::operator=(const CertificateRequest &from)
1860 {
1861 Algorithm::operator=(from);
1862 d = from.d;
1863 return *this;
1864 }
1865
isNull() const1866 bool CertificateRequest::isNull() const
1867 {
1868 return (!context() ? true : false);
1869 }
1870
canUseFormat(CertificateRequestFormat f,const QString & provider)1871 bool CertificateRequest::canUseFormat(CertificateRequestFormat f, const QString &provider)
1872 {
1873 CSRContext *c = static_cast<CSRContext *>(getContext(QStringLiteral("csr"), provider));
1874 bool ok = c->canUseFormat(f);
1875 delete c;
1876 return ok;
1877 }
1878
format() const1879 CertificateRequestFormat CertificateRequest::format() const
1880 {
1881 if (isNull())
1882 return PKCS10; // some default so we don't explode
1883 return static_cast<const CSRContext *>(context())->props()->format;
1884 }
1885
subjectInfo() const1886 CertificateInfo CertificateRequest::subjectInfo() const
1887 {
1888 return d->subjectInfoMap;
1889 }
1890
subjectInfoOrdered() const1891 CertificateInfoOrdered CertificateRequest::subjectInfoOrdered() const
1892 {
1893 return static_cast<const CSRContext *>(context())->props()->subject;
1894 }
1895
constraints() const1896 Constraints CertificateRequest::constraints() const
1897 {
1898 return static_cast<const CSRContext *>(context())->props()->constraints;
1899 }
1900
policies() const1901 QStringList CertificateRequest::policies() const
1902 {
1903 return static_cast<const CSRContext *>(context())->props()->policies;
1904 }
1905
subjectPublicKey() const1906 PublicKey CertificateRequest::subjectPublicKey() const
1907 {
1908 PKeyContext *c = static_cast<const CSRContext *>(context())->subjectPublicKey();
1909 PublicKey key;
1910 key.change(c);
1911 return key;
1912 }
1913
isCA() const1914 bool CertificateRequest::isCA() const
1915 {
1916 return static_cast<const CSRContext *>(context())->props()->isCA;
1917 }
1918
pathLimit() const1919 int CertificateRequest::pathLimit() const
1920 {
1921 return static_cast<const CSRContext *>(context())->props()->pathLimit;
1922 }
1923
challenge() const1924 QString CertificateRequest::challenge() const
1925 {
1926 return static_cast<const CSRContext *>(context())->props()->challenge;
1927 }
1928
signatureAlgorithm() const1929 SignatureAlgorithm CertificateRequest::signatureAlgorithm() const
1930 {
1931 return static_cast<const CSRContext *>(context())->props()->sigalgo;
1932 }
1933
operator ==(const CertificateRequest & otherCsr) const1934 bool CertificateRequest::operator==(const CertificateRequest &otherCsr) const
1935 {
1936 if (isNull()) {
1937 if (otherCsr.isNull())
1938 return true;
1939 else
1940 return false;
1941 } else if (otherCsr.isNull())
1942 return false;
1943
1944 const CSRContext *other = static_cast<const CSRContext *>(otherCsr.context());
1945 return static_cast<const CSRContext *>(context())->compare(other);
1946 }
1947
toDER() const1948 QByteArray CertificateRequest::toDER() const
1949 {
1950 return static_cast<const CSRContext *>(context())->toDER();
1951 }
1952
toPEM() const1953 QString CertificateRequest::toPEM() const
1954 {
1955 return static_cast<const CSRContext *>(context())->toPEM();
1956 }
1957
toPEMFile(const QString & fileName) const1958 bool CertificateRequest::toPEMFile(const QString &fileName) const
1959 {
1960 return stringToFile(fileName, toPEM());
1961 }
1962
fromDER(const QByteArray & a,ConvertResult * result,const QString & provider)1963 CertificateRequest CertificateRequest::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider)
1964 {
1965 CertificateRequest c;
1966 CSRContext * csr = static_cast<CSRContext *>(getContext(QStringLiteral("csr"), provider));
1967 ConvertResult r = csr->fromDER(a);
1968 if (result)
1969 *result = r;
1970 if (r == ConvertGood)
1971 c.change(csr);
1972 else
1973 delete csr;
1974 return c;
1975 }
1976
fromPEM(const QString & s,ConvertResult * result,const QString & provider)1977 CertificateRequest CertificateRequest::fromPEM(const QString &s, ConvertResult *result, const QString &provider)
1978 {
1979 CertificateRequest c;
1980 CSRContext * csr = static_cast<CSRContext *>(getContext(QStringLiteral("csr"), provider));
1981 ConvertResult r = csr->fromPEM(s);
1982 if (result)
1983 *result = r;
1984 if (r == ConvertGood)
1985 c.change(csr);
1986 else
1987 delete csr;
1988 return c;
1989 }
1990
1991 CertificateRequest
fromPEMFile(const QString & fileName,ConvertResult * result,const QString & provider)1992 CertificateRequest::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider)
1993 {
1994 QString pem;
1995 if (!stringFromFile(fileName, &pem)) {
1996 if (result)
1997 *result = ErrorFile;
1998 return CertificateRequest();
1999 }
2000 return fromPEM(pem, result, provider);
2001 }
2002
toString() const2003 QString CertificateRequest::toString() const
2004 {
2005 return static_cast<const CSRContext *>(context())->toSPKAC();
2006 }
2007
fromString(const QString & s,ConvertResult * result,const QString & provider)2008 CertificateRequest CertificateRequest::fromString(const QString &s, ConvertResult *result, const QString &provider)
2009 {
2010 CertificateRequest c;
2011 CSRContext * csr = static_cast<CSRContext *>(getContext(QStringLiteral("csr"), provider));
2012 ConvertResult r = csr->fromSPKAC(s);
2013 if (result)
2014 *result = r;
2015 if (r == ConvertGood)
2016 c.change(csr);
2017 else
2018 delete csr;
2019 return c;
2020 }
2021
change(CSRContext * c)2022 void CertificateRequest::change(CSRContext *c)
2023 {
2024 Algorithm::change(c);
2025 d->update(static_cast<CSRContext *>(context()));
2026 }
2027
2028 //----------------------------------------------------------------------------
2029 // CRLEntry
2030 //----------------------------------------------------------------------------
CRLEntry()2031 CRLEntry::CRLEntry()
2032 {
2033 _reason = Unspecified;
2034 }
2035
CRLEntry(const Certificate & c,Reason r)2036 CRLEntry::CRLEntry(const Certificate &c, Reason r)
2037 {
2038 _serial = c.serialNumber();
2039 _time = QDateTime::currentDateTime();
2040 _reason = r;
2041 }
2042
2043 // TODO make serial const & when we break ABI
CRLEntry(const BigInteger serial,const QDateTime & time,Reason r)2044 CRLEntry::CRLEntry(
2045 const BigInteger serial, // clazy:exclude=function-args-by-ref NOLINT(performance-unnecessary-value-param)
2046 const QDateTime &time,
2047 Reason r)
2048 {
2049 _serial = serial;
2050 _time = time;
2051 _reason = r;
2052 }
2053
CRLEntry(const CRLEntry & from)2054 CRLEntry::CRLEntry(const CRLEntry &from)
2055 : _serial(from._serial)
2056 , _time(from._time)
2057 , _reason(from._reason)
2058 {
2059 }
2060
~CRLEntry()2061 CRLEntry::~CRLEntry()
2062 {
2063 }
2064
operator =(const CRLEntry & from)2065 CRLEntry &CRLEntry::operator=(const CRLEntry &from)
2066 {
2067 _serial = from._serial;
2068 _time = from._time;
2069 _reason = from._reason;
2070 return *this;
2071 }
2072
isNull() const2073 bool CRLEntry::isNull() const
2074 {
2075 return (_time.isNull());
2076 }
2077
serialNumber() const2078 BigInteger CRLEntry::serialNumber() const
2079 {
2080 return _serial;
2081 }
2082
time() const2083 QDateTime CRLEntry::time() const
2084 {
2085 return _time;
2086 }
2087
reason() const2088 CRLEntry::Reason CRLEntry::reason() const
2089 {
2090 return _reason;
2091 }
2092
operator ==(const CRLEntry & otherEntry) const2093 bool CRLEntry::operator==(const CRLEntry &otherEntry) const
2094 {
2095 if (isNull()) {
2096 if (otherEntry.isNull())
2097 return true;
2098 else
2099 return false;
2100 } else if (otherEntry.isNull())
2101 return false;
2102
2103 if ((_serial != otherEntry._serial) || (_time != otherEntry._time) || (_reason != otherEntry._reason)) {
2104 return false;
2105 }
2106 return true;
2107 }
2108
operator <(const CRLEntry & otherEntry) const2109 bool CRLEntry::operator<(const CRLEntry &otherEntry) const
2110 {
2111 if (isNull() || otherEntry.isNull())
2112 return false;
2113
2114 if (_serial < otherEntry._serial)
2115 return true;
2116
2117 return false;
2118 }
2119
2120 //----------------------------------------------------------------------------
2121 // CRL
2122 //----------------------------------------------------------------------------
2123 class CRL::Private : public QSharedData
2124 {
2125 public:
2126 CertificateInfo issuerInfoMap;
2127
update(CRLContext * c)2128 void update(CRLContext *c)
2129 {
2130 if (c)
2131 issuerInfoMap = orderedToMap(c->props()->issuer);
2132 else
2133 issuerInfoMap = CertificateInfo();
2134 }
2135 };
2136
CRL()2137 CRL::CRL()
2138 : d(new Private)
2139 {
2140 }
2141
CRL(const CRL & from)2142 CRL::CRL(const CRL &from)
2143 : Algorithm(from)
2144 , d(from.d)
2145 {
2146 }
2147
~CRL()2148 CRL::~CRL()
2149 {
2150 }
2151
operator =(const CRL & from)2152 CRL &CRL::operator=(const CRL &from)
2153 {
2154 Algorithm::operator=(from);
2155 d = from.d;
2156 return *this;
2157 }
2158
isNull() const2159 bool CRL::isNull() const
2160 {
2161 return (!context() ? true : false);
2162 }
2163
issuerInfo() const2164 CertificateInfo CRL::issuerInfo() const
2165 {
2166 return d->issuerInfoMap;
2167 }
2168
issuerInfoOrdered() const2169 CertificateInfoOrdered CRL::issuerInfoOrdered() const
2170 {
2171 return static_cast<const CRLContext *>(context())->props()->issuer;
2172 }
2173
number() const2174 int CRL::number() const
2175 {
2176 return static_cast<const CRLContext *>(context())->props()->number;
2177 }
2178
thisUpdate() const2179 QDateTime CRL::thisUpdate() const
2180 {
2181 return static_cast<const CRLContext *>(context())->props()->thisUpdate;
2182 }
2183
nextUpdate() const2184 QDateTime CRL::nextUpdate() const
2185 {
2186 return static_cast<const CRLContext *>(context())->props()->nextUpdate;
2187 }
2188
revoked() const2189 QList<CRLEntry> CRL::revoked() const
2190 {
2191 return static_cast<const CRLContext *>(context())->props()->revoked;
2192 }
2193
signatureAlgorithm() const2194 SignatureAlgorithm CRL::signatureAlgorithm() const
2195 {
2196 return static_cast<const CRLContext *>(context())->props()->sigalgo;
2197 }
2198
issuerKeyId() const2199 QByteArray CRL::issuerKeyId() const
2200 {
2201 return static_cast<const CRLContext *>(context())->props()->issuerId;
2202 }
2203
toDER() const2204 QByteArray CRL::toDER() const
2205 {
2206 return static_cast<const CRLContext *>(context())->toDER();
2207 }
2208
toPEM() const2209 QString CRL::toPEM() const
2210 {
2211 return static_cast<const CRLContext *>(context())->toPEM();
2212 }
2213
operator ==(const CRL & otherCrl) const2214 bool CRL::operator==(const CRL &otherCrl) const
2215 {
2216 if (isNull()) {
2217 if (otherCrl.isNull())
2218 return true;
2219 else
2220 return false;
2221 } else if (otherCrl.isNull())
2222 return false;
2223
2224 const CRLContext *other = static_cast<const CRLContext *>(otherCrl.context());
2225 return static_cast<const CRLContext *>(context())->compare(other);
2226 }
2227
fromDER(const QByteArray & a,ConvertResult * result,const QString & provider)2228 CRL CRL::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider)
2229 {
2230 CRL c;
2231 CRLContext * cc = static_cast<CRLContext *>(getContext(QStringLiteral("crl"), provider));
2232 ConvertResult r = cc->fromDER(a);
2233 if (result)
2234 *result = r;
2235 if (r == ConvertGood)
2236 c.change(cc);
2237 else
2238 delete cc;
2239 return c;
2240 }
2241
fromPEM(const QString & s,ConvertResult * result,const QString & provider)2242 CRL CRL::fromPEM(const QString &s, ConvertResult *result, const QString &provider)
2243 {
2244 CRL c;
2245 CRLContext * cc = static_cast<CRLContext *>(getContext(QStringLiteral("crl"), provider));
2246 ConvertResult r = cc->fromPEM(s);
2247 if (result)
2248 *result = r;
2249 if (r == ConvertGood)
2250 c.change(cc);
2251 else
2252 delete cc;
2253 return c;
2254 }
2255
fromPEMFile(const QString & fileName,ConvertResult * result,const QString & provider)2256 CRL CRL::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider)
2257 {
2258 QString pem;
2259 if (!stringFromFile(fileName, &pem)) {
2260 if (result)
2261 *result = ErrorFile;
2262 return CRL();
2263 }
2264 return fromPEM(pem, result, provider);
2265 }
2266
toPEMFile(const QString & fileName) const2267 bool CRL::toPEMFile(const QString &fileName) const
2268 {
2269 return stringToFile(fileName, toPEM());
2270 }
2271
change(CRLContext * c)2272 void CRL::change(CRLContext *c)
2273 {
2274 Algorithm::change(c);
2275 d->update(static_cast<CRLContext *>(context()));
2276 }
2277
2278 //----------------------------------------------------------------------------
2279 // Store
2280 //----------------------------------------------------------------------------
2281 // CRL / X509 CRL
2282 // CERTIFICATE / X509 CERTIFICATE
readNextPem(QTextStream * ts,bool * isCRL)2283 static QString readNextPem(QTextStream *ts, bool *isCRL)
2284 {
2285 QString pem;
2286 bool crl = false;
2287 bool found = false;
2288 bool done = false;
2289 while (!ts->atEnd()) {
2290 const QString line = ts->readLine();
2291 if (!found) {
2292 if (line.startsWith(QLatin1String("-----BEGIN "))) {
2293 if (line.contains(QLatin1String("CERTIFICATE"))) {
2294 found = true;
2295 pem += line + QLatin1Char('\n');
2296 crl = false;
2297 } else if (line.contains(QLatin1String("CRL"))) {
2298 found = true;
2299 pem += line + QLatin1Char('\n');
2300 crl = true;
2301 }
2302 }
2303 } else {
2304 pem += line + QLatin1Char('\n');
2305 if (line.startsWith(QLatin1String("-----END "))) {
2306 done = true;
2307 break;
2308 }
2309 }
2310 }
2311 if (!done)
2312 return QString();
2313 if (isCRL)
2314 *isCRL = crl;
2315 return pem;
2316 }
2317
2318 class CertificateCollection::Private : public QSharedData
2319 {
2320 public:
2321 QList<Certificate> certs;
2322 QList<CRL> crls;
2323 };
2324
CertificateCollection()2325 CertificateCollection::CertificateCollection()
2326 : d(new Private)
2327 {
2328 }
2329
CertificateCollection(const CertificateCollection & from)2330 CertificateCollection::CertificateCollection(const CertificateCollection &from)
2331 : d(from.d)
2332 {
2333 }
2334
~CertificateCollection()2335 CertificateCollection::~CertificateCollection()
2336 {
2337 }
2338
operator =(const CertificateCollection & from)2339 CertificateCollection &CertificateCollection::operator=(const CertificateCollection &from)
2340 {
2341 d = from.d;
2342 return *this;
2343 }
2344
addCertificate(const Certificate & cert)2345 void CertificateCollection::addCertificate(const Certificate &cert)
2346 {
2347 d->certs.append(cert);
2348 }
2349
addCRL(const CRL & crl)2350 void CertificateCollection::addCRL(const CRL &crl)
2351 {
2352 d->crls.append(crl);
2353 }
2354
certificates() const2355 QList<Certificate> CertificateCollection::certificates() const
2356 {
2357 return d->certs;
2358 }
2359
crls() const2360 QList<CRL> CertificateCollection::crls() const
2361 {
2362 return d->crls;
2363 }
2364
append(const CertificateCollection & other)2365 void CertificateCollection::append(const CertificateCollection &other)
2366 {
2367 d->certs += other.d->certs;
2368 d->crls += other.d->crls;
2369 }
2370
operator +(const CertificateCollection & other) const2371 CertificateCollection CertificateCollection::operator+(const CertificateCollection &other) const
2372 {
2373 CertificateCollection c = *this;
2374 c.append(other);
2375 return c;
2376 }
2377
operator +=(const CertificateCollection & other)2378 CertificateCollection &CertificateCollection::operator+=(const CertificateCollection &other)
2379 {
2380 append(other);
2381 return *this;
2382 }
2383
canUsePKCS7(const QString & provider)2384 bool CertificateCollection::canUsePKCS7(const QString &provider)
2385 {
2386 return isSupported("certcollection", provider);
2387 }
2388
toFlatTextFile(const QString & fileName)2389 bool CertificateCollection::toFlatTextFile(const QString &fileName)
2390 {
2391 QFile f(fileName);
2392 if (!f.open(QFile::WriteOnly))
2393 return false;
2394
2395 QTextStream ts(&f);
2396 int n;
2397 for (n = 0; n < d->certs.count(); ++n)
2398 ts << d->certs[n].toPEM();
2399 for (n = 0; n < d->crls.count(); ++n)
2400 ts << d->crls[n].toPEM();
2401 return true;
2402 }
2403
toPKCS7File(const QString & fileName,const QString & provider)2404 bool CertificateCollection::toPKCS7File(const QString &fileName, const QString &provider)
2405 {
2406 CertCollectionContext *col =
2407 static_cast<CertCollectionContext *>(getContext(QStringLiteral("certcollection"), provider));
2408
2409 QList<CertContext *> cert_list;
2410 QList<CRLContext *> crl_list;
2411 int n;
2412 for (n = 0; n < d->certs.count(); ++n) {
2413 CertContext *c = static_cast<CertContext *>(d->certs[n].context());
2414 cert_list += c;
2415 }
2416 for (n = 0; n < d->crls.count(); ++n) {
2417 CRLContext *c = static_cast<CRLContext *>(d->crls[n].context());
2418 crl_list += c;
2419 }
2420
2421 const QByteArray result = col->toPKCS7(cert_list, crl_list);
2422 delete col;
2423
2424 return arrayToFile(fileName, result);
2425 }
2426
2427 CertificateCollection
fromFlatTextFile(const QString & fileName,ConvertResult * result,const QString & provider)2428 CertificateCollection::fromFlatTextFile(const QString &fileName, ConvertResult *result, const QString &provider)
2429 {
2430 QFile f(fileName);
2431 if (!f.open(QFile::ReadOnly)) {
2432 if (result)
2433 *result = ErrorFile;
2434 return CertificateCollection();
2435 }
2436
2437 CertificateCollection certs;
2438 QTextStream ts(&f);
2439 while (true) {
2440 bool isCRL = false;
2441 QString pem = readNextPem(&ts, &isCRL);
2442 if (pem.isNull())
2443 break;
2444 if (isCRL) {
2445 CRL c = CRL::fromPEM(pem, nullptr, provider);
2446 if (!c.isNull())
2447 certs.addCRL(c);
2448 } else {
2449 Certificate c = Certificate::fromPEM(pem, nullptr, provider);
2450 if (!c.isNull())
2451 certs.addCertificate(c);
2452 }
2453 }
2454
2455 if (result)
2456 *result = ConvertGood;
2457
2458 return certs;
2459 }
2460
2461 CertificateCollection
fromPKCS7File(const QString & fileName,ConvertResult * result,const QString & provider)2462 CertificateCollection::fromPKCS7File(const QString &fileName, ConvertResult *result, const QString &provider)
2463 {
2464 QByteArray der;
2465 if (!arrayFromFile(fileName, &der)) {
2466 if (result)
2467 *result = ErrorFile;
2468 return CertificateCollection();
2469 }
2470
2471 CertificateCollection certs;
2472
2473 QList<CertContext *> cert_list;
2474 QList<CRLContext *> crl_list;
2475 CertCollectionContext *col =
2476 static_cast<CertCollectionContext *>(getContext(QStringLiteral("certcollection"), provider));
2477 ConvertResult r = col->fromPKCS7(der, &cert_list, &crl_list);
2478 delete col;
2479
2480 if (result)
2481 *result = r;
2482 if (r == ConvertGood) {
2483 int n;
2484 for (n = 0; n < cert_list.count(); ++n) {
2485 Certificate c;
2486 c.change(cert_list[n]);
2487 certs.addCertificate(c);
2488 }
2489 for (n = 0; n < crl_list.count(); ++n) {
2490 CRL c;
2491 c.change(crl_list[n]);
2492 certs.addCRL(c);
2493 }
2494 }
2495 return certs;
2496 }
2497
2498 //----------------------------------------------------------------------------
2499 // CertificateAuthority
2500 //----------------------------------------------------------------------------
CertificateAuthority(const Certificate & cert,const PrivateKey & key,const QString & provider)2501 CertificateAuthority::CertificateAuthority(const Certificate &cert, const PrivateKey &key, const QString &provider)
2502 : Algorithm(QStringLiteral("ca"), provider)
2503 {
2504 static_cast<CAContext *>(context())->setup(*(static_cast<const CertContext *>(cert.context())),
2505 *(static_cast<const PKeyContext *>(key.context())));
2506 }
2507
CertificateAuthority(const CertificateAuthority & from)2508 CertificateAuthority::CertificateAuthority(const CertificateAuthority &from)
2509 : Algorithm(from)
2510 {
2511 }
2512
~CertificateAuthority()2513 CertificateAuthority::~CertificateAuthority()
2514 {
2515 }
2516
operator =(const CertificateAuthority & from)2517 CertificateAuthority &CertificateAuthority::operator=(const CertificateAuthority &from)
2518 {
2519 Algorithm::operator=(from);
2520 return *this;
2521 }
2522
certificate() const2523 Certificate CertificateAuthority::certificate() const
2524 {
2525 Certificate c;
2526 c.change(static_cast<const CAContext *>(context())->certificate());
2527 return c;
2528 }
2529
signRequest(const CertificateRequest & req,const QDateTime & notValidAfter) const2530 Certificate CertificateAuthority::signRequest(const CertificateRequest &req, const QDateTime ¬ValidAfter) const
2531 {
2532 Certificate c;
2533 CertContext *cc = static_cast<const CAContext *>(context())->signRequest(
2534 *(static_cast<const CSRContext *>(req.context())), notValidAfter);
2535 if (cc)
2536 c.change(cc);
2537 return c;
2538 }
2539
createCRL(const QDateTime & nextUpdate) const2540 CRL CertificateAuthority::createCRL(const QDateTime &nextUpdate) const
2541 {
2542 CRL crl;
2543 CRLContext *cc = static_cast<const CAContext *>(context())->createCRL(nextUpdate);
2544 if (cc)
2545 crl.change(cc);
2546 return crl;
2547 }
2548
updateCRL(const CRL & crl,const QList<CRLEntry> & entries,const QDateTime & nextUpdate) const2549 CRL CertificateAuthority::updateCRL(const CRL &crl, const QList<CRLEntry> &entries, const QDateTime &nextUpdate) const
2550 {
2551 CRL new_crl;
2552 CRLContext *cc = static_cast<const CAContext *>(context())->updateCRL(
2553 *(static_cast<const CRLContext *>(crl.context())), entries, nextUpdate);
2554 if (cc)
2555 new_crl.change(cc);
2556 return new_crl;
2557 }
2558
2559 //----------------------------------------------------------------------------
2560 // KeyBundle
2561 //----------------------------------------------------------------------------
2562 class KeyBundle::Private : public QSharedData
2563 {
2564 public:
2565 QString name;
2566 CertificateChain chain;
2567 PrivateKey key;
2568 };
2569
KeyBundle()2570 KeyBundle::KeyBundle()
2571 : d(new Private)
2572 {
2573 }
2574
KeyBundle(const QString & fileName,const SecureArray & passphrase)2575 KeyBundle::KeyBundle(const QString &fileName, const SecureArray &passphrase)
2576 : d(new Private)
2577 {
2578 *this = fromFile(fileName, passphrase, nullptr, QString());
2579 }
2580
KeyBundle(const KeyBundle & from)2581 KeyBundle::KeyBundle(const KeyBundle &from)
2582 : d(from.d)
2583 {
2584 }
2585
~KeyBundle()2586 KeyBundle::~KeyBundle()
2587 {
2588 }
2589
operator =(const KeyBundle & from)2590 KeyBundle &KeyBundle::operator=(const KeyBundle &from)
2591 {
2592 d = from.d;
2593 return *this;
2594 }
2595
isNull() const2596 bool KeyBundle::isNull() const
2597 {
2598 return d->chain.isEmpty();
2599 }
2600
name() const2601 QString KeyBundle::name() const
2602 {
2603 return d->name;
2604 }
2605
certificateChain() const2606 CertificateChain KeyBundle::certificateChain() const
2607 {
2608 return d->chain;
2609 }
2610
privateKey() const2611 PrivateKey KeyBundle::privateKey() const
2612 {
2613 return d->key;
2614 }
2615
setName(const QString & s)2616 void KeyBundle::setName(const QString &s)
2617 {
2618 d->name = s;
2619 }
2620
setCertificateChainAndKey(const CertificateChain & c,const PrivateKey & key)2621 void KeyBundle::setCertificateChainAndKey(const CertificateChain &c, const PrivateKey &key)
2622 {
2623 d->chain = c;
2624 d->key = key;
2625 }
2626
toArray(const SecureArray & passphrase,const QString & provider) const2627 QByteArray KeyBundle::toArray(const SecureArray &passphrase, const QString &provider) const
2628 {
2629 PKCS12Context *pix = static_cast<PKCS12Context *>(getContext(QStringLiteral("pkcs12"), provider));
2630
2631 QList<const CertContext *> list;
2632 for (int n = 0; n < d->chain.count(); ++n)
2633 list.append(static_cast<const CertContext *>(d->chain[n].context()));
2634 const QByteArray buf =
2635 pix->toPKCS12(d->name, list, *(static_cast<const PKeyContext *>(d->key.context())), passphrase);
2636 delete pix;
2637
2638 return buf;
2639 }
2640
toFile(const QString & fileName,const SecureArray & passphrase,const QString & provider) const2641 bool KeyBundle::toFile(const QString &fileName, const SecureArray &passphrase, const QString &provider) const
2642 {
2643 return arrayToFile(fileName, toArray(passphrase, provider));
2644 }
2645
2646 KeyBundle
fromArray(const QByteArray & a,const SecureArray & passphrase,ConvertResult * result,const QString & provider)2647 KeyBundle::fromArray(const QByteArray &a, const SecureArray &passphrase, ConvertResult *result, const QString &provider)
2648 {
2649 KeyBundle bundle;
2650 get_pkcs12_der(
2651 a, QString(), (void *)&a, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key);
2652 return bundle;
2653 }
2654
fromFile(const QString & fileName,const SecureArray & passphrase,ConvertResult * result,const QString & provider)2655 KeyBundle KeyBundle::fromFile(const QString & fileName,
2656 const SecureArray &passphrase,
2657 ConvertResult * result,
2658 const QString & provider)
2659 {
2660 QByteArray der;
2661 if (!arrayFromFile(fileName, &der)) {
2662 if (result)
2663 *result = ErrorFile;
2664 return KeyBundle();
2665 }
2666
2667 KeyBundle bundle;
2668 get_pkcs12_der(
2669 der, fileName, nullptr, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key);
2670 return bundle;
2671 }
2672
2673 //----------------------------------------------------------------------------
2674 // PGPKey
2675 //----------------------------------------------------------------------------
PGPKey()2676 PGPKey::PGPKey()
2677 {
2678 }
2679
PGPKey(const QString & fileName)2680 PGPKey::PGPKey(const QString &fileName)
2681 {
2682 *this = fromFile(fileName, nullptr, QString());
2683 }
2684
PGPKey(const PGPKey & from)2685 PGPKey::PGPKey(const PGPKey &from)
2686 : Algorithm(from)
2687 {
2688 }
2689
~PGPKey()2690 PGPKey::~PGPKey()
2691 {
2692 }
2693
operator =(const PGPKey & from)2694 PGPKey &PGPKey::operator=(const PGPKey &from)
2695 {
2696 Algorithm::operator=(from);
2697 return *this;
2698 }
2699
isNull() const2700 bool PGPKey::isNull() const
2701 {
2702 return (!context() ? true : false);
2703 }
2704
keyId() const2705 QString PGPKey::keyId() const
2706 {
2707 return static_cast<const PGPKeyContext *>(context())->props()->keyId;
2708 }
2709
primaryUserId() const2710 QString PGPKey::primaryUserId() const
2711 {
2712 return static_cast<const PGPKeyContext *>(context())->props()->userIds.first();
2713 }
2714
userIds() const2715 QStringList PGPKey::userIds() const
2716 {
2717 return static_cast<const PGPKeyContext *>(context())->props()->userIds;
2718 }
2719
isSecret() const2720 bool PGPKey::isSecret() const
2721 {
2722 return static_cast<const PGPKeyContext *>(context())->props()->isSecret;
2723 }
2724
creationDate() const2725 QDateTime PGPKey::creationDate() const
2726 {
2727 return static_cast<const PGPKeyContext *>(context())->props()->creationDate;
2728 }
2729
expirationDate() const2730 QDateTime PGPKey::expirationDate() const
2731 {
2732 return static_cast<const PGPKeyContext *>(context())->props()->expirationDate;
2733 }
2734
fingerprint() const2735 QString PGPKey::fingerprint() const
2736 {
2737 return static_cast<const PGPKeyContext *>(context())->props()->fingerprint;
2738 }
2739
inKeyring() const2740 bool PGPKey::inKeyring() const
2741 {
2742 return static_cast<const PGPKeyContext *>(context())->props()->inKeyring;
2743 }
2744
isTrusted() const2745 bool PGPKey::isTrusted() const
2746 {
2747 return static_cast<const PGPKeyContext *>(context())->props()->isTrusted;
2748 }
2749
toArray() const2750 QByteArray PGPKey::toArray() const
2751 {
2752 return static_cast<const PGPKeyContext *>(context())->toBinary();
2753 }
2754
toString() const2755 QString PGPKey::toString() const
2756 {
2757 return static_cast<const PGPKeyContext *>(context())->toAscii();
2758 }
2759
toFile(const QString & fileName) const2760 bool PGPKey::toFile(const QString &fileName) const
2761 {
2762 return stringToFile(fileName, toString());
2763 }
2764
fromArray(const QByteArray & a,ConvertResult * result,const QString & provider)2765 PGPKey PGPKey::fromArray(const QByteArray &a, ConvertResult *result, const QString &provider)
2766 {
2767 PGPKey k;
2768 PGPKeyContext *kc = static_cast<PGPKeyContext *>(getContext(QStringLiteral("pgpkey"), provider));
2769 ConvertResult r = kc->fromBinary(a);
2770 if (result)
2771 *result = r;
2772 if (r == ConvertGood)
2773 k.change(kc);
2774 else
2775 delete kc;
2776 return k;
2777 }
2778
fromString(const QString & s,ConvertResult * result,const QString & provider)2779 PGPKey PGPKey::fromString(const QString &s, ConvertResult *result, const QString &provider)
2780 {
2781 PGPKey k;
2782 PGPKeyContext *kc = static_cast<PGPKeyContext *>(getContext(QStringLiteral("pgpkey"), provider));
2783 ConvertResult r = kc->fromAscii(s);
2784 if (result)
2785 *result = r;
2786 if (r == ConvertGood)
2787 k.change(kc);
2788 else
2789 delete kc;
2790 return k;
2791 }
2792
fromFile(const QString & fileName,ConvertResult * result,const QString & provider)2793 PGPKey PGPKey::fromFile(const QString &fileName, ConvertResult *result, const QString &provider)
2794 {
2795 QString str;
2796 if (!stringFromFile(fileName, &str)) {
2797 if (result)
2798 *result = ErrorFile;
2799 return PGPKey();
2800 }
2801 return fromString(str, result, provider);
2802 }
2803
2804 //----------------------------------------------------------------------------
2805 // KeyLoader
2806 //----------------------------------------------------------------------------
2807 class KeyLoaderThread : public QThread
2808 {
2809 Q_OBJECT
2810 public:
2811 enum Type
2812 {
2813 PKPEMFile,
2814 PKPEM,
2815 PKDER,
2816 KBDERFile,
2817 KBDER
2818 };
2819
2820 class In
2821 {
2822 public:
2823 Type type;
2824 QString fileName, pem;
2825 SecureArray der;
2826 QByteArray kbder;
2827 };
2828
2829 class Out
2830 {
2831 public:
2832 ConvertResult convertResult;
2833 PrivateKey privateKey;
2834 KeyBundle keyBundle;
2835 };
2836
2837 In in;
2838 Out out;
2839
KeyLoaderThread(QObject * parent=nullptr)2840 KeyLoaderThread(QObject *parent = nullptr)
2841 : QThread(parent)
2842 {
2843 }
2844
2845 protected:
run()2846 void run() override
2847 {
2848 if (in.type == PKPEMFile)
2849 out.privateKey = PrivateKey::fromPEMFile(in.fileName, SecureArray(), &out.convertResult);
2850 else if (in.type == PKPEM)
2851 out.privateKey = PrivateKey::fromPEM(in.pem, SecureArray(), &out.convertResult);
2852 else if (in.type == PKDER)
2853 out.privateKey = PrivateKey::fromDER(in.der, SecureArray(), &out.convertResult);
2854 else if (in.type == KBDERFile)
2855 out.keyBundle = KeyBundle::fromFile(in.fileName, SecureArray(), &out.convertResult);
2856 else if (in.type == KBDER)
2857 out.keyBundle = KeyBundle::fromArray(in.kbder, SecureArray(), &out.convertResult);
2858 }
2859 };
2860
2861 class KeyLoader::Private : public QObject
2862 {
2863 Q_OBJECT
2864 public:
2865 KeyLoader *q;
2866
2867 bool active;
2868 KeyLoaderThread * thread;
2869 KeyLoaderThread::In in;
2870 KeyLoaderThread::Out out;
2871
Private(KeyLoader * _q)2872 Private(KeyLoader *_q)
2873 : QObject(_q)
2874 , q(_q)
2875 {
2876 active = false;
2877 }
2878
reset()2879 void reset()
2880 {
2881 in = KeyLoaderThread::In();
2882 out = KeyLoaderThread::Out();
2883 }
2884
start()2885 void start()
2886 {
2887 active = true;
2888 thread = new KeyLoaderThread(this);
2889 // used queued for signal-safety
2890 connect(thread, &KeyLoaderThread::finished, this, &KeyLoader::Private::thread_finished, Qt::QueuedConnection);
2891 thread->in = in;
2892 thread->start();
2893 }
2894
2895 private Q_SLOTS:
thread_finished()2896 void thread_finished()
2897 {
2898 out = thread->out;
2899 delete thread;
2900 thread = nullptr;
2901 active = false;
2902
2903 emit q->finished();
2904 }
2905 };
2906
KeyLoader(QObject * parent)2907 KeyLoader::KeyLoader(QObject *parent)
2908 : QObject(parent)
2909 {
2910 d = new Private(this);
2911 }
2912
~KeyLoader()2913 KeyLoader::~KeyLoader()
2914 {
2915 delete d;
2916 }
2917
loadPrivateKeyFromPEMFile(const QString & fileName)2918 void KeyLoader::loadPrivateKeyFromPEMFile(const QString &fileName)
2919 {
2920 Q_ASSERT(!d->active);
2921 if (d->active)
2922 return;
2923
2924 d->reset();
2925 d->in.type = KeyLoaderThread::PKPEMFile;
2926 d->in.fileName = fileName;
2927 d->start();
2928 }
2929
loadPrivateKeyFromPEM(const QString & s)2930 void KeyLoader::loadPrivateKeyFromPEM(const QString &s)
2931 {
2932 Q_ASSERT(!d->active);
2933 if (d->active)
2934 return;
2935
2936 d->reset();
2937 d->in.type = KeyLoaderThread::PKPEM;
2938 d->in.pem = s;
2939 d->start();
2940 }
2941
loadPrivateKeyFromDER(const SecureArray & a)2942 void KeyLoader::loadPrivateKeyFromDER(const SecureArray &a)
2943 {
2944 Q_ASSERT(!d->active);
2945 if (d->active)
2946 return;
2947
2948 d->reset();
2949 d->in.type = KeyLoaderThread::PKDER;
2950 d->in.der = a;
2951 d->start();
2952 }
2953
loadKeyBundleFromFile(const QString & fileName)2954 void KeyLoader::loadKeyBundleFromFile(const QString &fileName)
2955 {
2956 Q_ASSERT(!d->active);
2957 if (d->active)
2958 return;
2959
2960 d->reset();
2961 d->in.type = KeyLoaderThread::KBDERFile;
2962 d->in.fileName = fileName;
2963 d->start();
2964 }
2965
loadKeyBundleFromArray(const QByteArray & a)2966 void KeyLoader::loadKeyBundleFromArray(const QByteArray &a)
2967 {
2968 Q_ASSERT(!d->active);
2969 if (d->active)
2970 return;
2971
2972 d->reset();
2973 d->in.type = KeyLoaderThread::KBDERFile;
2974 d->in.kbder = a;
2975 d->start();
2976 }
2977
convertResult() const2978 ConvertResult KeyLoader::convertResult() const
2979 {
2980 return d->out.convertResult;
2981 }
2982
privateKey() const2983 PrivateKey KeyLoader::privateKey() const
2984 {
2985 return d->out.privateKey;
2986 }
2987
keyBundle() const2988 KeyBundle KeyLoader::keyBundle() const
2989 {
2990 return d->out.keyBundle;
2991 }
2992
2993 }
2994
2995 #include "qca_cert.moc"
2996