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 &notValidAfter) 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