File indexing completed on 2024-04-21 08:33:08

0001 /*
0002  * Copyright (C) 2003-2007  Justin Karneges <justin@affinix.com>
0003  * Copyright (C) 2004-2006  Brad Hards <bradh@frogmouth.net>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Lesser General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2.1 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Lesser General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Lesser General Public
0016  * License along with this library; if not, write to the Free Software
0017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0018  * 02110-1301  USA
0019  *
0020  */
0021 
0022 #include "qca_cert.h"
0023 
0024 #include "qca_publickey.h"
0025 #include "qcaprovider.h"
0026 
0027 #include <QFile>
0028 #include <QRegExp>
0029 #include <QRegularExpression>
0030 #include <QTextStream>
0031 #include <QUrl>
0032 
0033 #include <cstdlib>
0034 
0035 namespace QCA {
0036 
0037 Provider::Context *getContext(const QString &type, const QString &provider);
0038 Provider::Context *getContext(const QString &type, Provider *p);
0039 
0040 // from qca_publickey.cpp
0041 bool         stringToFile(const QString &fileName, const QString &content);
0042 bool         stringFromFile(const QString &fileName, QString *s);
0043 bool         arrayToFile(const QString &fileName, const QByteArray &content);
0044 bool         arrayFromFile(const QString &fileName, QByteArray *a);
0045 bool         ask_passphrase(const QString &fname, void *ptr, SecureArray *answer);
0046 ProviderList allProviders();
0047 Provider    *providerForName(const QString &name);
0048 bool         use_asker_fallback(ConvertResult r);
0049 
0050 // last 3 arguments must be valid, and chain must be empty
0051 static bool get_pkcs12_der(const QByteArray  &der,
0052                            const QString     &fileName,
0053                            void              *ptr,
0054                            const SecureArray &passphrase,
0055                            ConvertResult     *result,
0056                            const QString     &provider,
0057                            QString           *name,
0058                            CertificateChain  *chain,
0059                            PrivateKey        *key)
0060 {
0061     QString              _name;
0062     QList<CertContext *> list;
0063     PKeyContext         *kc = nullptr;
0064 
0065     PKCS12Context *pix = static_cast<PKCS12Context *>(getContext(QStringLiteral("pkcs12"), provider));
0066     ConvertResult  r   = pix->fromPKCS12(der, passphrase, &_name, &list, &kc);
0067 
0068     // error converting without passphrase?  maybe a passphrase is needed
0069     if (use_asker_fallback(r) && passphrase.isEmpty()) {
0070         SecureArray pass;
0071         if (ask_passphrase(fileName, ptr, &pass))
0072             r = pix->fromPKCS12(der, pass, &_name, &list, &kc);
0073     }
0074     delete pix;
0075 
0076     if (result)
0077         *result = r;
0078 
0079     if (r == ConvertGood) {
0080         *name = _name;
0081         for (int n = 0; n < list.count(); ++n) {
0082             Certificate cert;
0083             cert.change(list[n]);
0084             chain->append(cert);
0085         }
0086         key->change(kc);
0087         return true;
0088     }
0089     return false;
0090 }
0091 
0092 static CertificateInfo orderedToMap(const CertificateInfoOrdered &info)
0093 {
0094     CertificateInfo out;
0095 
0096     // first, do all but EmailLegacy
0097     for (int n = 0; n < info.count(); ++n) {
0098         const CertificateInfoPair &i = info[n];
0099         if (i.type().known() != EmailLegacy)
0100             out.insert(i.type(), i.value());
0101     }
0102 
0103     // lastly, apply EmailLegacy
0104     for (int n = 0; n < info.count(); ++n) {
0105         const CertificateInfoPair &i = info[n];
0106         if (i.type().known() == EmailLegacy) {
0107             // de-dup
0108             const QList<QString> emails = out.values(Email);
0109             if (!emails.contains(i.value()))
0110                 out.insert(Email, i.value());
0111         }
0112     }
0113 
0114     return out;
0115 }
0116 
0117 static void moveMapValues(CertificateInfo *from, CertificateInfoOrdered *to, const CertificateInfoType &type)
0118 {
0119     const QList<QString> values = from->values(type);
0120     from->remove(type);
0121 
0122     // multimap values are stored in reverse.  we'll insert backwards in
0123     //   order to right them.
0124     for (int n = values.count() - 1; n >= 0; --n)
0125         to->append(CertificateInfoPair(type, values[n]));
0126 }
0127 
0128 static CertificateInfoOrdered mapToOrdered(const CertificateInfo &info)
0129 {
0130     CertificateInfo        in = info;
0131     CertificateInfoOrdered out;
0132 
0133     // have a specific order for some types
0134     moveMapValues(&in, &out, CommonName);
0135     moveMapValues(&in, &out, Country);
0136     moveMapValues(&in, &out, Locality);
0137     moveMapValues(&in, &out, State);
0138     moveMapValues(&in, &out, Organization);
0139     moveMapValues(&in, &out, OrganizationalUnit);
0140     moveMapValues(&in, &out, Email);
0141     moveMapValues(&in, &out, URI);
0142     moveMapValues(&in, &out, DNS);
0143     moveMapValues(&in, &out, IPAddress);
0144     moveMapValues(&in, &out, XMPP);
0145 
0146     // get remaining types
0147     const QList<CertificateInfoType> typesLeft = in.keys();
0148 
0149     // dedup
0150     QList<CertificateInfoType> types;
0151     for (int n = 0; n < typesLeft.count(); ++n) {
0152         if (!types.contains(typesLeft[n]))
0153             types += typesLeft[n];
0154     }
0155 
0156     // insert the rest of the types in the order we got them (map order)
0157     for (int n = 0; n < types.count(); ++n)
0158         moveMapValues(&in, &out, types[n]);
0159 
0160     Q_ASSERT(in.isEmpty());
0161 
0162     return out;
0163 }
0164 
0165 //----------------------------------------------------------------------------
0166 // Global
0167 //----------------------------------------------------------------------------
0168 static const char CommonName_id[]            = "2.5.4.3";
0169 static const char Email_id[]                 = "GeneralName.rfc822Name";
0170 static const char EmailLegacy_id[]           = "1.2.840.113549.1.9.1";
0171 static const char Organization_id[]          = "2.5.4.10";
0172 static const char OrganizationalUnit_id[]    = "2.5.4.11";
0173 static const char Locality_id[]              = "2.5.4.7";
0174 static const char IncorporationLocality_id[] = "1.3.6.1.4.1.311.60.2.1.1";
0175 static const char State_id[]                 = "2.5.4.8";
0176 static const char IncorporationState_id[]    = "1.3.6.1.4.1.311.60.2.1.2";
0177 static const char Country_id[]               = "2.5.4.6";
0178 static const char IncorporationCountry_id[]  = "1.3.6.1.4.1.311.60.2.1.3";
0179 static const char URI_id[]                   = "GeneralName.uniformResourceIdentifier";
0180 static const char DNS_id[]                   = "GeneralName.dNSName";
0181 static const char IPAddress_id[]             = "GeneralName.iPAddress";
0182 static const char XMPP_id[]                  = "1.3.6.1.5.5.7.8.5";
0183 
0184 static const char DigitalSignature_id[]   = "KeyUsage.digitalSignature";
0185 static const char NonRepudiation_id[]     = "KeyUsage.nonRepudiation";
0186 static const char KeyEncipherment_id[]    = "KeyUsage.keyEncipherment";
0187 static const char DataEncipherment_id[]   = "KeyUsage.dataEncipherment";
0188 static const char KeyAgreement_id[]       = "KeyUsage.keyAgreement";
0189 static const char KeyCertificateSign_id[] = "KeyUsage.keyCertSign";
0190 static const char CRLSign_id[]            = "KeyUsage.crlSign";
0191 static const char EncipherOnly_id[]       = "KeyUsage.encipherOnly";
0192 static const char DecipherOnly_id[]       = "KeyUsage.decipherOnly";
0193 static const char ServerAuth_id[]         = "1.3.6.1.5.5.7.3.1";
0194 static const char ClientAuth_id[]         = "1.3.6.1.5.5.7.3.2";
0195 static const char CodeSigning_id[]        = "1.3.6.1.5.5.7.3.3";
0196 static const char EmailProtection_id[]    = "1.3.6.1.5.5.7.3.4";
0197 static const char IPSecEndSystem_id[]     = "1.3.6.1.5.5.7.3.5";
0198 static const char IPSecTunnel_id[]        = "1.3.6.1.5.5.7.3.6";
0199 static const char IPSecUser_id[]          = "1.3.6.1.5.5.7.3.7";
0200 static const char TimeStamping_id[]       = "1.3.6.1.5.5.7.3.8";
0201 static const char OCSPSigning_id[]        = "1.3.6.1.5.5.7.3.9";
0202 
0203 static QString knownToId(CertificateInfoTypeKnown k)
0204 {
0205     const char *out = nullptr;
0206     switch (k) {
0207     case CommonName:
0208         out = CommonName_id;
0209         break;
0210     case Email:
0211         out = Email_id;
0212         break;
0213     case EmailLegacy:
0214         out = EmailLegacy_id;
0215         break;
0216     case Organization:
0217         out = Organization_id;
0218         break;
0219     case OrganizationalUnit:
0220         out = OrganizationalUnit_id;
0221         break;
0222     case Locality:
0223         out = Locality_id;
0224         break;
0225     case IncorporationLocality:
0226         out = IncorporationLocality_id;
0227         break;
0228     case State:
0229         out = State_id;
0230         break;
0231     case IncorporationState:
0232         out = IncorporationState_id;
0233         break;
0234     case Country:
0235         out = Country_id;
0236         break;
0237     case IncorporationCountry:
0238         out = IncorporationCountry_id;
0239         break;
0240     case URI:
0241         out = URI_id;
0242         break;
0243     case DNS:
0244         out = DNS_id;
0245         break;
0246     case IPAddress:
0247         out = IPAddress_id;
0248         break;
0249     case XMPP:
0250         out = XMPP_id;
0251         break;
0252     }
0253     Q_ASSERT(out);
0254     if (!out)
0255         abort();
0256     return QString::fromLatin1(out);
0257 }
0258 
0259 static int idToKnown(const QString &id)
0260 {
0261     if (id == QLatin1String(CommonName_id))
0262         return CommonName;
0263     else if (id == QLatin1String(Email_id))
0264         return Email;
0265     else if (id == QLatin1String(EmailLegacy_id))
0266         return EmailLegacy;
0267     else if (id == QLatin1String(Organization_id))
0268         return Organization;
0269     else if (id == QLatin1String(OrganizationalUnit_id))
0270         return OrganizationalUnit;
0271     else if (id == QLatin1String(Locality_id))
0272         return Locality;
0273     else if (id == QLatin1String(IncorporationLocality_id))
0274         return IncorporationLocality;
0275     else if (id == QLatin1String(State_id))
0276         return State;
0277     else if (id == QLatin1String(IncorporationState_id))
0278         return IncorporationState;
0279     else if (id == QLatin1String(Country_id))
0280         return Country;
0281     else if (id == QLatin1String(IncorporationCountry_id))
0282         return IncorporationCountry;
0283     else if (id == QLatin1String(URI_id))
0284         return URI;
0285     else if (id == QLatin1String(DNS_id))
0286         return DNS;
0287     else if (id == QLatin1String(IPAddress_id))
0288         return IPAddress;
0289     else if (id == QLatin1String(XMPP_id))
0290         return XMPP;
0291     else
0292         return -1;
0293 }
0294 
0295 static CertificateInfoType::Section knownToSection(CertificateInfoTypeKnown k)
0296 {
0297     switch (k) {
0298     case CommonName:
0299     case EmailLegacy:
0300     case Organization:
0301     case OrganizationalUnit:
0302     case Locality:
0303     case IncorporationLocality:
0304     case State:
0305     case IncorporationState:
0306     case Country:
0307     case IncorporationCountry:
0308         return CertificateInfoType::DN;
0309     default:
0310         break;
0311     }
0312     return CertificateInfoType::AlternativeName;
0313 }
0314 
0315 static const char *knownToShortName(CertificateInfoTypeKnown k)
0316 {
0317     switch (k) {
0318     case CommonName:
0319         return "CN";
0320     case Locality:
0321         return "L";
0322     case State:
0323         return "ST";
0324     case Organization:
0325         return "O";
0326     case OrganizationalUnit:
0327         return "OU";
0328     case Country:
0329         return "C";
0330     case EmailLegacy:
0331         return "emailAddress";
0332     default:
0333         break;
0334     }
0335     return nullptr;
0336 }
0337 
0338 static QString constraintKnownToId(ConstraintTypeKnown k)
0339 {
0340     const char *out = nullptr;
0341     switch (k) {
0342     case DigitalSignature:
0343         out = DigitalSignature_id;
0344         break;
0345     case NonRepudiation:
0346         out = NonRepudiation_id;
0347         break;
0348     case KeyEncipherment:
0349         out = KeyEncipherment_id;
0350         break;
0351     case DataEncipherment:
0352         out = DataEncipherment_id;
0353         break;
0354     case KeyAgreement:
0355         out = KeyAgreement_id;
0356         break;
0357     case KeyCertificateSign:
0358         out = KeyCertificateSign_id;
0359         break;
0360     case CRLSign:
0361         out = CRLSign_id;
0362         break;
0363     case EncipherOnly:
0364         out = EncipherOnly_id;
0365         break;
0366     case DecipherOnly:
0367         out = DecipherOnly_id;
0368         break;
0369     case ServerAuth:
0370         out = ServerAuth_id;
0371         break;
0372     case ClientAuth:
0373         out = ClientAuth_id;
0374         break;
0375     case CodeSigning:
0376         out = CodeSigning_id;
0377         break;
0378     case EmailProtection:
0379         out = EmailProtection_id;
0380         break;
0381     case IPSecEndSystem:
0382         out = IPSecEndSystem_id;
0383         break;
0384     case IPSecTunnel:
0385         out = IPSecTunnel_id;
0386         break;
0387     case IPSecUser:
0388         out = IPSecUser_id;
0389         break;
0390     case TimeStamping:
0391         out = TimeStamping_id;
0392         break;
0393     case OCSPSigning:
0394         out = OCSPSigning_id;
0395         break;
0396     }
0397     Q_ASSERT(out);
0398     if (!out)
0399         abort();
0400     return QString::fromLatin1(out);
0401 }
0402 
0403 static int constraintIdToKnown(const QString &id)
0404 {
0405     if (id == QLatin1String(DigitalSignature_id))
0406         return DigitalSignature;
0407     else if (id == QLatin1String(NonRepudiation_id))
0408         return NonRepudiation;
0409     else if (id == QLatin1String(KeyEncipherment_id))
0410         return KeyEncipherment;
0411     else if (id == QLatin1String(DataEncipherment_id))
0412         return DataEncipherment;
0413     else if (id == QLatin1String(KeyAgreement_id))
0414         return KeyAgreement;
0415     else if (id == QLatin1String(KeyCertificateSign_id))
0416         return KeyCertificateSign;
0417     else if (id == QLatin1String(CRLSign_id))
0418         return CRLSign;
0419     else if (id == QLatin1String(EncipherOnly_id))
0420         return EncipherOnly;
0421     else if (id == QLatin1String(DecipherOnly_id))
0422         return DecipherOnly;
0423     else if (id == QLatin1String(ServerAuth_id))
0424         return ServerAuth;
0425     else if (id == QLatin1String(ClientAuth_id))
0426         return ClientAuth;
0427     else if (id == QLatin1String(CodeSigning_id))
0428         return CodeSigning;
0429     else if (id == QLatin1String(EmailProtection_id))
0430         return EmailProtection;
0431     else if (id == QLatin1String(IPSecEndSystem_id))
0432         return IPSecEndSystem;
0433     else if (id == QLatin1String(IPSecTunnel_id))
0434         return IPSecTunnel;
0435     else if (id == QLatin1String(IPSecUser_id))
0436         return IPSecUser;
0437     else if (id == QLatin1String(TimeStamping_id))
0438         return TimeStamping;
0439     else if (id == QLatin1String(OCSPSigning_id))
0440         return OCSPSigning;
0441     else
0442         return -1;
0443 }
0444 
0445 static ConstraintType::Section constraintKnownToSection(ConstraintTypeKnown k)
0446 {
0447     switch (k) {
0448     case DigitalSignature:
0449     case NonRepudiation:
0450     case KeyEncipherment:
0451     case DataEncipherment:
0452     case KeyAgreement:
0453     case KeyCertificateSign:
0454     case CRLSign:
0455     case EncipherOnly:
0456     case DecipherOnly:
0457         return ConstraintType::KeyUsage;
0458     default:
0459         break;
0460     }
0461     return ConstraintType::ExtendedKeyUsage;
0462 }
0463 
0464 static QString dnLabel(const CertificateInfoType &type)
0465 {
0466     const char *str = knownToShortName(type.known());
0467     if (str)
0468         return QString::fromLatin1(str);
0469 
0470     const QString id = type.id();
0471     // is it an oid?
0472     if (id[0].isDigit())
0473         return QStringLiteral("OID.") + id;
0474 
0475     return QStringLiteral("qca.") + id;
0476 }
0477 
0478 QString orderedToDNString(const CertificateInfoOrdered &in)
0479 {
0480     QStringList parts;
0481     foreach (const CertificateInfoPair &i, in) {
0482         if (i.type().section() != CertificateInfoType::DN)
0483             continue;
0484 
0485         const QString name = dnLabel(i.type());
0486         parts += name + QLatin1Char('=') + i.value();
0487     }
0488     return parts.join(QStringLiteral(", "));
0489 }
0490 
0491 CertificateInfoOrdered orderedDNOnly(const CertificateInfoOrdered &in)
0492 {
0493     CertificateInfoOrdered out;
0494     for (int n = 0; n < in.count(); ++n) {
0495         if (in[n].type().section() == CertificateInfoType::DN)
0496             out += in[n];
0497     }
0498     return out;
0499 }
0500 
0501 static QString baseCertName(const CertificateInfo &info)
0502 {
0503     QString str = info.value(CommonName);
0504     if (str.isEmpty()) {
0505         str = info.value(Organization);
0506         if (str.isEmpty())
0507             str = QStringLiteral("Unnamed");
0508     }
0509     return str;
0510 }
0511 
0512 static QList<int> findSameName(const QString &name, const QStringList &list)
0513 {
0514     QList<int> out;
0515     for (int n = 0; n < list.count(); ++n) {
0516         if (list[n] == name)
0517             out += n;
0518     }
0519     return out;
0520 }
0521 
0522 static QString
0523 uniqueSubjectValue(const CertificateInfoType &type, const QList<int> &items, const QList<Certificate> &certs, int i)
0524 {
0525     QStringList vals = certs[items[i]].subjectInfo().values(type);
0526     if (!vals.isEmpty()) {
0527         foreach (int n, items) {
0528             if (n == items[i])
0529                 continue;
0530 
0531             const QStringList other_vals = certs[n].subjectInfo().values(type);
0532             for (int k = 0; k < vals.count(); ++k) {
0533                 if (other_vals.contains(vals[k])) {
0534                     vals.removeAt(k);
0535                     break;
0536                 }
0537             }
0538 
0539             if (vals.isEmpty())
0540                 break;
0541         }
0542 
0543         if (!vals.isEmpty())
0544             return vals[0];
0545     }
0546 
0547     return QString();
0548 }
0549 
0550 static QString uniqueIssuerName(const QList<int> &items, const QList<Certificate> &certs, int i)
0551 {
0552     const QString val = baseCertName(certs[items[i]].issuerInfo());
0553 
0554     bool found = false;
0555     foreach (int n, items) {
0556         if (n == items[i])
0557             continue;
0558 
0559         const QString other_val = baseCertName(certs[n].issuerInfo());
0560         if (other_val == val) {
0561             found = true;
0562             break;
0563         }
0564     }
0565 
0566     if (!found)
0567         return val;
0568 
0569     return QString();
0570 }
0571 
0572 static const char *constraintToString(const ConstraintType &type)
0573 {
0574     switch (type.known()) {
0575     case DigitalSignature:
0576         return "DigitalSignature";
0577     case NonRepudiation:
0578         return "NonRepudiation";
0579     case KeyEncipherment:
0580         return "KeyEncipherment";
0581     case DataEncipherment:
0582         return "DataEncipherment";
0583     case KeyAgreement:
0584         return "KeyAgreement";
0585     case KeyCertificateSign:
0586         return "KeyCertificateSign";
0587     case CRLSign:
0588         return "CRLSign";
0589     case EncipherOnly:
0590         return "EncipherOnly";
0591     case DecipherOnly:
0592         return "DecipherOnly";
0593     case ServerAuth:
0594         return "ServerAuth";
0595     case ClientAuth:
0596         return "ClientAuth";
0597     case CodeSigning:
0598         return "CodeSigning";
0599     case EmailProtection:
0600         return "EmailProtection";
0601     case IPSecEndSystem:
0602         return "IPSecEndSystem";
0603     case IPSecTunnel:
0604         return "IPSecTunnel";
0605     case IPSecUser:
0606         return "IPSecUser";
0607     case TimeStamping:
0608         return "TimeStamping";
0609     case OCSPSigning:
0610         return "OCSPSigning";
0611     }
0612     return nullptr;
0613 }
0614 
0615 static QString
0616 uniqueConstraintValue(const ConstraintType &type, const QList<int> &items, const QList<Certificate> &certs, int i)
0617 {
0618     if (certs[items[i]].constraints().contains(type)) {
0619         bool found = false;
0620         foreach (int n, items) {
0621             if (n == items[i])
0622                 continue;
0623 
0624             Constraints other_vals = certs[n].constraints();
0625             if (other_vals.contains(type)) {
0626                 found = true;
0627                 break;
0628             }
0629         }
0630 
0631         if (!found)
0632             return QString::fromLatin1(constraintToString(type));
0633     }
0634 
0635     return QString();
0636 }
0637 
0638 static QString makeUniqueName(const QList<int> &items, const QStringList &list, const QList<Certificate> &certs, int i)
0639 {
0640     QString str, name;
0641 
0642     // different organization?
0643     str = uniqueSubjectValue(Organization, items, certs, i);
0644     if (!str.isEmpty()) {
0645         name = list[items[i]] + QStringLiteral(" of ") + str;
0646         goto end;
0647     }
0648 
0649     // different organizational unit?
0650     str = uniqueSubjectValue(OrganizationalUnit, items, certs, i);
0651     if (!str.isEmpty()) {
0652         name = list[items[i]] + QStringLiteral(" of ") + str;
0653         goto end;
0654     }
0655 
0656     // different email address?
0657     str = uniqueSubjectValue(Email, items, certs, i);
0658     if (!str.isEmpty()) {
0659         name = list[items[i]] + QStringLiteral(" <") + str + QLatin1Char('>');
0660         goto end;
0661     }
0662 
0663     // different xmpp addresses?
0664     str = uniqueSubjectValue(XMPP, items, certs, i);
0665     if (!str.isEmpty()) {
0666         name = list[items[i]] + QStringLiteral(" <xmpp:") + str + QLatin1Char('>');
0667         goto end;
0668     }
0669 
0670     // different issuers?
0671     str = uniqueIssuerName(items, certs, i);
0672     if (!str.isEmpty()) {
0673         name = list[items[i]] + QStringLiteral(" by ") + str;
0674         goto end;
0675     }
0676 
0677     // different usages?
0678 
0679     // DigitalSignature
0680     str = uniqueConstraintValue(DigitalSignature, items, certs, i);
0681     if (!str.isEmpty()) {
0682         name = list[items[i]] + QStringLiteral(" for ") + str;
0683         goto end;
0684     }
0685 
0686     // ClientAuth
0687     str = uniqueConstraintValue(ClientAuth, items, certs, i);
0688     if (!str.isEmpty()) {
0689         name = list[items[i]] + QStringLiteral(" for ") + str;
0690         goto end;
0691     }
0692 
0693     // EmailProtection
0694     str = uniqueConstraintValue(EmailProtection, items, certs, i);
0695     if (!str.isEmpty()) {
0696         name = list[items[i]] + QStringLiteral(" for ") + str;
0697         goto end;
0698     }
0699 
0700     // DataEncipherment
0701     str = uniqueConstraintValue(DataEncipherment, items, certs, i);
0702     if (!str.isEmpty()) {
0703         name = list[items[i]] + QStringLiteral(" for ") + str;
0704         goto end;
0705     }
0706 
0707     // EncipherOnly
0708     str = uniqueConstraintValue(EncipherOnly, items, certs, i);
0709     if (!str.isEmpty()) {
0710         name = list[items[i]] + QStringLiteral(" for ") + str;
0711         goto end;
0712     }
0713 
0714     // DecipherOnly
0715     str = uniqueConstraintValue(DecipherOnly, items, certs, i);
0716     if (!str.isEmpty()) {
0717         name = list[items[i]] + QStringLiteral(" for ") + str;
0718         goto end;
0719     }
0720 
0721     // if there's nothing easily unique, then do a DN string
0722     name = certs[items[i]].subjectInfoOrdered().toString();
0723 
0724 end:
0725     return name;
0726 }
0727 
0728 QStringList makeFriendlyNames(const QList<Certificate> &list)
0729 {
0730     QStringList names;
0731 
0732     // give a base name to all certs first
0733     foreach (const Certificate &cert, list)
0734         names += baseCertName(cert.subjectInfo());
0735 
0736     // come up with a collision list
0737     QList<QList<int>> itemCollisions;
0738     foreach (const QString &name, names) {
0739         // anyone else using this name?
0740         const QList<int> items = findSameName(name, names);
0741         if (items.count() > 1) {
0742             // don't save duplicate collisions
0743             bool haveAlready = false;
0744             foreach (const QList<int> &other, itemCollisions) {
0745                 foreach (int n, items) {
0746                     if (other.contains(n)) {
0747                         haveAlready = true;
0748                         break;
0749                     }
0750                 }
0751 
0752                 if (haveAlready)
0753                     break;
0754             }
0755 
0756             if (haveAlready)
0757                 continue;
0758 
0759             itemCollisions += items;
0760         }
0761     }
0762 
0763     // resolve collisions by providing extra details
0764     foreach (const QList<int> &items, itemCollisions) {
0765         // printf("%d items are using [%s]\n", items.count(), qPrintable(names[items[0]]));
0766 
0767         for (int n = 0; n < items.count(); ++n) {
0768             names[items[n]] = makeUniqueName(items, names, list, n);
0769             // printf("  %d: reassigning: [%s]\n", items[n], qPrintable(names[items[n]]));
0770         }
0771     }
0772 
0773     return names;
0774 }
0775 
0776 //----------------------------------------------------------------------------
0777 // CertificateInfoType
0778 //----------------------------------------------------------------------------
0779 class CertificateInfoType::Private : public QSharedData
0780 {
0781 public:
0782     CertificateInfoType::Section section;
0783     int                          known;
0784     QString                      id;
0785 
0786     Private()
0787         : section(CertificateInfoType::DN)
0788         , known(-1)
0789     {
0790     }
0791 };
0792 
0793 CertificateInfoType::CertificateInfoType()
0794     : d(new Private)
0795 {
0796 }
0797 
0798 CertificateInfoType::CertificateInfoType(CertificateInfoTypeKnown known)
0799     : d(new Private)
0800 {
0801     d->section = knownToSection(known);
0802     d->known   = known;
0803     d->id      = knownToId(known); // always valid
0804 }
0805 
0806 CertificateInfoType::CertificateInfoType(const QString &id, Section section)
0807     : d(new Private)
0808 {
0809     d->section = section;
0810     d->known   = idToKnown(id); // can be -1 for unknown
0811     d->id      = id;
0812 }
0813 
0814 CertificateInfoType::CertificateInfoType(const CertificateInfoType &from)
0815     : d(from.d)
0816 {
0817 }
0818 
0819 CertificateInfoType::~CertificateInfoType()
0820 {
0821 }
0822 
0823 CertificateInfoType &CertificateInfoType::operator=(const CertificateInfoType &from)
0824 {
0825     d = from.d;
0826     return *this;
0827 }
0828 
0829 CertificateInfoType::Section CertificateInfoType::section() const
0830 {
0831     return d->section;
0832 }
0833 
0834 CertificateInfoTypeKnown CertificateInfoType::known() const
0835 {
0836     return (CertificateInfoTypeKnown)d->known;
0837 }
0838 
0839 QString CertificateInfoType::id() const
0840 {
0841     return d->id;
0842 }
0843 
0844 bool CertificateInfoType::operator<(const CertificateInfoType &other) const
0845 {
0846     // sort by knowns (in enum order), then by ids (in string order)
0847     if (d->known != -1) {
0848         if (other.d->known == -1)
0849             return true;
0850         else if (d->known < other.d->known)
0851             return true;
0852         else
0853             return false;
0854     } else {
0855         if (other.d->known != -1)
0856             return false;
0857         else if (d->id < other.d->id)
0858             return true;
0859         else
0860             return false;
0861     }
0862 }
0863 
0864 bool CertificateInfoType::operator==(const CertificateInfoType &other) const
0865 {
0866     // are both known types?
0867     if (d->known != -1 && other.d->known != -1) {
0868         // if so, compare the ints
0869         if (d->known != other.d->known)
0870             return false;
0871     } else {
0872         // otherwise, compare the string ids
0873         if (d->id != other.d->id)
0874             return false;
0875     }
0876 
0877     if (d->section != other.d->section)
0878         return false;
0879 
0880     return true;
0881 }
0882 
0883 //----------------------------------------------------------------------------
0884 // CertificateInfoPair
0885 //----------------------------------------------------------------------------
0886 class CertificateInfoPair::Private : public QSharedData
0887 {
0888 public:
0889     CertificateInfoType type;
0890     QString             value;
0891 };
0892 
0893 CertificateInfoPair::CertificateInfoPair()
0894     : d(new Private)
0895 {
0896 }
0897 
0898 CertificateInfoPair::CertificateInfoPair(const CertificateInfoType &type, const QString &value)
0899     : d(new Private)
0900 {
0901     d->type  = type;
0902     d->value = value;
0903 }
0904 
0905 CertificateInfoPair::CertificateInfoPair(const CertificateInfoPair &from)
0906     : d(from.d)
0907 {
0908 }
0909 
0910 CertificateInfoPair::~CertificateInfoPair()
0911 {
0912 }
0913 
0914 CertificateInfoPair &CertificateInfoPair::operator=(const CertificateInfoPair &from)
0915 {
0916     d = from.d;
0917     return *this;
0918 }
0919 
0920 CertificateInfoType CertificateInfoPair::type() const
0921 {
0922     return d->type;
0923 }
0924 
0925 QString CertificateInfoPair::value() const
0926 {
0927     return d->value;
0928 }
0929 
0930 bool CertificateInfoPair::operator==(const CertificateInfoPair &other) const
0931 {
0932     if (d->type == other.d->type && d->value == other.d->value)
0933         return true;
0934     return false;
0935 }
0936 
0937 //----------------------------------------------------------------------------
0938 // ConstraintType
0939 //----------------------------------------------------------------------------
0940 class ConstraintType::Private : public QSharedData
0941 {
0942 public:
0943     ConstraintType::Section section;
0944     int                     known;
0945     QString                 id;
0946 
0947     Private()
0948         : section(ConstraintType::KeyUsage)
0949         , known(-1)
0950     {
0951     }
0952 };
0953 
0954 ConstraintType::ConstraintType()
0955     : d(new Private)
0956 {
0957 }
0958 
0959 ConstraintType::ConstraintType(ConstraintTypeKnown known)
0960     : d(new Private)
0961 {
0962     d->section = constraintKnownToSection(known);
0963     d->known   = known;
0964     d->id      = constraintKnownToId(known); // always valid
0965 }
0966 
0967 ConstraintType::ConstraintType(const QString &id, Section section)
0968     : d(new Private)
0969 {
0970     d->section = section;
0971     d->known   = constraintIdToKnown(id); // can be -1 for unknown
0972     d->id      = id;
0973 }
0974 
0975 ConstraintType::ConstraintType(const ConstraintType &from)
0976     : d(from.d)
0977 {
0978 }
0979 
0980 ConstraintType::~ConstraintType()
0981 {
0982 }
0983 
0984 ConstraintType &ConstraintType::operator=(const ConstraintType &from)
0985 {
0986     d = from.d;
0987     return *this;
0988 }
0989 
0990 ConstraintType::Section ConstraintType::section() const
0991 {
0992     return d->section;
0993 }
0994 
0995 ConstraintTypeKnown ConstraintType::known() const
0996 {
0997     return (ConstraintTypeKnown)d->known;
0998 }
0999 
1000 QString ConstraintType::id() const
1001 {
1002     return d->id;
1003 }
1004 
1005 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 
1025 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 
1063     Private()
1064         : isCA(false)
1065         , pathLimit(0)
1066     {
1067     }
1068 };
1069 
1070 CertificateOptions::CertificateOptions(CertificateRequestFormat f)
1071 {
1072     d         = new Private;
1073     d->format = f;
1074 }
1075 
1076 CertificateOptions::CertificateOptions(const CertificateOptions &from)
1077 {
1078     d = new Private(*from.d);
1079 }
1080 
1081 CertificateOptions::~CertificateOptions()
1082 {
1083     delete d;
1084 }
1085 
1086 CertificateOptions &CertificateOptions::operator=(const CertificateOptions &from)
1087 {
1088     *d = *from.d;
1089     return *this;
1090 }
1091 
1092 CertificateRequestFormat CertificateOptions::format() const
1093 {
1094     return d->format;
1095 }
1096 
1097 void CertificateOptions::setFormat(CertificateRequestFormat f)
1098 {
1099     d->format = f;
1100 }
1101 
1102 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 
1114 QString CertificateOptions::challenge() const
1115 {
1116     return d->challenge;
1117 }
1118 
1119 CertificateInfo CertificateOptions::info() const
1120 {
1121     return d->infoMap;
1122 }
1123 
1124 CertificateInfoOrdered CertificateOptions::infoOrdered() const
1125 {
1126     return d->info;
1127 }
1128 
1129 Constraints CertificateOptions::constraints() const
1130 {
1131     return d->constraints;
1132 }
1133 
1134 QStringList CertificateOptions::policies() const
1135 {
1136     return d->policies;
1137 }
1138 
1139 QStringList CertificateOptions::crlLocations() const
1140 {
1141     return d->crlLocations;
1142 }
1143 
1144 QStringList CertificateOptions::issuerLocations() const
1145 {
1146     return d->issuerLocations;
1147 }
1148 
1149 QStringList CertificateOptions::ocspLocations() const
1150 {
1151     return d->ocspLocations;
1152 }
1153 
1154 bool CertificateOptions::isCA() const
1155 {
1156     return d->isCA;
1157 }
1158 
1159 int CertificateOptions::pathLimit() const
1160 {
1161     return d->pathLimit;
1162 }
1163 
1164 BigInteger CertificateOptions::serialNumber() const
1165 {
1166     return d->serial;
1167 }
1168 
1169 QDateTime CertificateOptions::notValidBefore() const
1170 {
1171     return d->start;
1172 }
1173 
1174 QDateTime CertificateOptions::notValidAfter() const
1175 {
1176     return d->end;
1177 }
1178 
1179 void CertificateOptions::setChallenge(const QString &s)
1180 {
1181     d->challenge = s;
1182 }
1183 
1184 void CertificateOptions::setInfo(const CertificateInfo &info)
1185 {
1186     d->info    = mapToOrdered(info);
1187     d->infoMap = info;
1188 }
1189 
1190 void CertificateOptions::setInfoOrdered(const CertificateInfoOrdered &info)
1191 {
1192     d->info    = info;
1193     d->infoMap = orderedToMap(info);
1194 }
1195 
1196 void CertificateOptions::setConstraints(const Constraints &constraints)
1197 {
1198     d->constraints = constraints;
1199 }
1200 
1201 void CertificateOptions::setPolicies(const QStringList &policies)
1202 {
1203     d->policies = policies;
1204 }
1205 
1206 void CertificateOptions::setCRLLocations(const QStringList &locations)
1207 {
1208     d->crlLocations = locations;
1209 }
1210 
1211 void CertificateOptions::setIssuerLocations(const QStringList &locations)
1212 {
1213     d->issuerLocations = locations;
1214 }
1215 
1216 void CertificateOptions::setOCSPLocations(const QStringList &locations)
1217 {
1218     d->ocspLocations = locations;
1219 }
1220 
1221 void CertificateOptions::setAsCA(int pathLimit)
1222 {
1223     d->isCA      = true;
1224     d->pathLimit = pathLimit;
1225 }
1226 
1227 void CertificateOptions::setAsUser()
1228 {
1229     d->isCA      = false;
1230     d->pathLimit = 0;
1231 }
1232 
1233 void CertificateOptions::setSerialNumber(const BigInteger &i)
1234 {
1235     d->serial = i;
1236 }
1237 
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
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
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
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 
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 
1451 Certificate::Certificate()
1452     : d(new Private)
1453 {
1454 }
1455 
1456 Certificate::Certificate(const QString &fileName)
1457     : d(new Private)
1458 {
1459     *this = fromPEMFile(fileName, nullptr, QString());
1460 }
1461 
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 
1472 Certificate::Certificate(const Certificate &from)
1473     : Algorithm(from)
1474     , d(from.d)
1475 {
1476 }
1477 
1478 Certificate::~Certificate()
1479 {
1480 }
1481 
1482 Certificate &Certificate::operator=(const Certificate &from)
1483 {
1484     Algorithm::operator=(from);
1485     d = from.d;
1486     return *this;
1487 }
1488 
1489 bool Certificate::isNull() const
1490 {
1491     return (!context() ? true : false);
1492 }
1493 
1494 QDateTime Certificate::notValidBefore() const
1495 {
1496     return static_cast<const CertContext *>(context())->props()->start;
1497 }
1498 
1499 QDateTime Certificate::notValidAfter() const
1500 {
1501     return static_cast<const CertContext *>(context())->props()->end;
1502 }
1503 
1504 CertificateInfo Certificate::subjectInfo() const
1505 {
1506     return d->subjectInfoMap;
1507 }
1508 
1509 CertificateInfoOrdered Certificate::subjectInfoOrdered() const
1510 {
1511     return static_cast<const CertContext *>(context())->props()->subject;
1512 }
1513 
1514 CertificateInfo Certificate::issuerInfo() const
1515 {
1516     return d->issuerInfoMap;
1517 }
1518 
1519 CertificateInfoOrdered Certificate::issuerInfoOrdered() const
1520 {
1521     return static_cast<const CertContext *>(context())->props()->issuer;
1522 }
1523 
1524 Constraints Certificate::constraints() const
1525 {
1526     return static_cast<const CertContext *>(context())->props()->constraints;
1527 }
1528 
1529 QStringList Certificate::policies() const
1530 {
1531     return static_cast<const CertContext *>(context())->props()->policies;
1532 }
1533 
1534 QStringList Certificate::crlLocations() const
1535 {
1536     return static_cast<const CertContext *>(context())->props()->crlLocations;
1537 }
1538 
1539 QStringList Certificate::issuerLocations() const
1540 {
1541     return static_cast<const CertContext *>(context())->props()->issuerLocations;
1542 }
1543 
1544 QStringList Certificate::ocspLocations() const
1545 {
1546     return static_cast<const CertContext *>(context())->props()->ocspLocations;
1547 }
1548 
1549 QString Certificate::commonName() const
1550 {
1551     return d->subjectInfoMap.value(CommonName);
1552 }
1553 
1554 BigInteger Certificate::serialNumber() const
1555 {
1556     return static_cast<const CertContext *>(context())->props()->serial;
1557 }
1558 
1559 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 
1567 bool Certificate::isCA() const
1568 {
1569     return static_cast<const CertContext *>(context())->props()->isCA;
1570 }
1571 
1572 bool Certificate::isSelfSigned() const
1573 {
1574     return static_cast<const CertContext *>(context())->props()->isSelfSigned;
1575 }
1576 
1577 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 
1583 int Certificate::pathLimit() const
1584 {
1585     return static_cast<const CertContext *>(context())->props()->pathLimit;
1586 }
1587 
1588 SignatureAlgorithm Certificate::signatureAlgorithm() const
1589 {
1590     return static_cast<const CertContext *>(context())->props()->sigalgo;
1591 }
1592 
1593 QByteArray Certificate::subjectKeyId() const
1594 {
1595     return static_cast<const CertContext *>(context())->props()->subjectId;
1596 }
1597 
1598 QByteArray Certificate::issuerKeyId() const
1599 {
1600     return static_cast<const CertContext *>(context())->props()->issuerId;
1601 }
1602 
1603 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 
1618 QByteArray Certificate::toDER() const
1619 {
1620     return static_cast<const CertContext *>(context())->toDER();
1621 }
1622 
1623 QString Certificate::toPEM() const
1624 {
1625     return static_cast<const CertContext *>(context())->toPEM();
1626 }
1627 
1628 bool Certificate::toPEMFile(const QString &fileName) const
1629 {
1630     return stringToFile(fileName, toPEM());
1631 }
1632 
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 
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 
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
1674 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 
1722 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 
1736 void Certificate::change(CertContext *c)
1737 {
1738     Algorithm::change(c);
1739     d->update(static_cast<CertContext *>(context()));
1740 }
1741 
1742 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
1773 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 
1819     void update(CSRContext *c)
1820     {
1821         if (c)
1822             subjectInfoMap = orderedToMap(c->props()->subject);
1823         else
1824             subjectInfoMap = CertificateInfo();
1825     }
1826 };
1827 
1828 CertificateRequest::CertificateRequest()
1829     : d(new Private)
1830 {
1831 }
1832 
1833 CertificateRequest::CertificateRequest(const QString &fileName)
1834     : d(new Private)
1835 {
1836     *this = fromPEMFile(fileName, nullptr, QString());
1837 }
1838 
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 
1849 CertificateRequest::CertificateRequest(const CertificateRequest &from)
1850     : Algorithm(from)
1851     , d(from.d)
1852 {
1853 }
1854 
1855 CertificateRequest::~CertificateRequest()
1856 {
1857 }
1858 
1859 CertificateRequest &CertificateRequest::operator=(const CertificateRequest &from)
1860 {
1861     Algorithm::operator=(from);
1862     d = from.d;
1863     return *this;
1864 }
1865 
1866 bool CertificateRequest::isNull() const
1867 {
1868     return (!context() ? true : false);
1869 }
1870 
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 
1879 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 
1886 CertificateInfo CertificateRequest::subjectInfo() const
1887 {
1888     return d->subjectInfoMap;
1889 }
1890 
1891 CertificateInfoOrdered CertificateRequest::subjectInfoOrdered() const
1892 {
1893     return static_cast<const CSRContext *>(context())->props()->subject;
1894 }
1895 
1896 Constraints CertificateRequest::constraints() const
1897 {
1898     return static_cast<const CSRContext *>(context())->props()->constraints;
1899 }
1900 
1901 QStringList CertificateRequest::policies() const
1902 {
1903     return static_cast<const CSRContext *>(context())->props()->policies;
1904 }
1905 
1906 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 
1914 bool CertificateRequest::isCA() const
1915 {
1916     return static_cast<const CSRContext *>(context())->props()->isCA;
1917 }
1918 
1919 int CertificateRequest::pathLimit() const
1920 {
1921     return static_cast<const CSRContext *>(context())->props()->pathLimit;
1922 }
1923 
1924 QString CertificateRequest::challenge() const
1925 {
1926     return static_cast<const CSRContext *>(context())->props()->challenge;
1927 }
1928 
1929 SignatureAlgorithm CertificateRequest::signatureAlgorithm() const
1930 {
1931     return static_cast<const CSRContext *>(context())->props()->sigalgo;
1932 }
1933 
1934 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 
1948 QByteArray CertificateRequest::toDER() const
1949 {
1950     return static_cast<const CSRContext *>(context())->toDER();
1951 }
1952 
1953 QString CertificateRequest::toPEM() const
1954 {
1955     return static_cast<const CSRContext *>(context())->toPEM();
1956 }
1957 
1958 bool CertificateRequest::toPEMFile(const QString &fileName) const
1959 {
1960     return stringToFile(fileName, toPEM());
1961 }
1962 
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 
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
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 
2003 QString CertificateRequest::toString() const
2004 {
2005     return static_cast<const CSRContext *>(context())->toSPKAC();
2006 }
2007 
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 
2022 void CertificateRequest::change(CSRContext *c)
2023 {
2024     Algorithm::change(c);
2025     d->update(static_cast<CSRContext *>(context()));
2026 }
2027 
2028 //----------------------------------------------------------------------------
2029 // CRLEntry
2030 //----------------------------------------------------------------------------
2031 CRLEntry::CRLEntry()
2032 {
2033     _reason = Unspecified;
2034 }
2035 
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
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 
2054 CRLEntry::CRLEntry(const CRLEntry &from)
2055     : _serial(from._serial)
2056     , _time(from._time)
2057     , _reason(from._reason)
2058 {
2059 }
2060 
2061 CRLEntry::~CRLEntry()
2062 {
2063 }
2064 
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 
2073 bool CRLEntry::isNull() const
2074 {
2075     return (_time.isNull());
2076 }
2077 
2078 BigInteger CRLEntry::serialNumber() const
2079 {
2080     return _serial;
2081 }
2082 
2083 QDateTime CRLEntry::time() const
2084 {
2085     return _time;
2086 }
2087 
2088 CRLEntry::Reason CRLEntry::reason() const
2089 {
2090     return _reason;
2091 }
2092 
2093 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 
2109 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 
2128     void update(CRLContext *c)
2129     {
2130         if (c)
2131             issuerInfoMap = orderedToMap(c->props()->issuer);
2132         else
2133             issuerInfoMap = CertificateInfo();
2134     }
2135 };
2136 
2137 CRL::CRL()
2138     : d(new Private)
2139 {
2140 }
2141 
2142 CRL::CRL(const CRL &from)
2143     : Algorithm(from)
2144     , d(from.d)
2145 {
2146 }
2147 
2148 CRL::~CRL()
2149 {
2150 }
2151 
2152 CRL &CRL::operator=(const CRL &from)
2153 {
2154     Algorithm::operator=(from);
2155     d = from.d;
2156     return *this;
2157 }
2158 
2159 bool CRL::isNull() const
2160 {
2161     return (!context() ? true : false);
2162 }
2163 
2164 CertificateInfo CRL::issuerInfo() const
2165 {
2166     return d->issuerInfoMap;
2167 }
2168 
2169 CertificateInfoOrdered CRL::issuerInfoOrdered() const
2170 {
2171     return static_cast<const CRLContext *>(context())->props()->issuer;
2172 }
2173 
2174 int CRL::number() const
2175 {
2176     return static_cast<const CRLContext *>(context())->props()->number;
2177 }
2178 
2179 QDateTime CRL::thisUpdate() const
2180 {
2181     return static_cast<const CRLContext *>(context())->props()->thisUpdate;
2182 }
2183 
2184 QDateTime CRL::nextUpdate() const
2185 {
2186     return static_cast<const CRLContext *>(context())->props()->nextUpdate;
2187 }
2188 
2189 QList<CRLEntry> CRL::revoked() const
2190 {
2191     return static_cast<const CRLContext *>(context())->props()->revoked;
2192 }
2193 
2194 SignatureAlgorithm CRL::signatureAlgorithm() const
2195 {
2196     return static_cast<const CRLContext *>(context())->props()->sigalgo;
2197 }
2198 
2199 QByteArray CRL::issuerKeyId() const
2200 {
2201     return static_cast<const CRLContext *>(context())->props()->issuerId;
2202 }
2203 
2204 QByteArray CRL::toDER() const
2205 {
2206     return static_cast<const CRLContext *>(context())->toDER();
2207 }
2208 
2209 QString CRL::toPEM() const
2210 {
2211     return static_cast<const CRLContext *>(context())->toPEM();
2212 }
2213 
2214 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 
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 
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 
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 
2267 bool CRL::toPEMFile(const QString &fileName) const
2268 {
2269     return stringToFile(fileName, toPEM());
2270 }
2271 
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
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 
2325 CertificateCollection::CertificateCollection()
2326     : d(new Private)
2327 {
2328 }
2329 
2330 CertificateCollection::CertificateCollection(const CertificateCollection &from)
2331     : d(from.d)
2332 {
2333 }
2334 
2335 CertificateCollection::~CertificateCollection()
2336 {
2337 }
2338 
2339 CertificateCollection &CertificateCollection::operator=(const CertificateCollection &from)
2340 {
2341     d = from.d;
2342     return *this;
2343 }
2344 
2345 void CertificateCollection::addCertificate(const Certificate &cert)
2346 {
2347     d->certs.append(cert);
2348 }
2349 
2350 void CertificateCollection::addCRL(const CRL &crl)
2351 {
2352     d->crls.append(crl);
2353 }
2354 
2355 QList<Certificate> CertificateCollection::certificates() const
2356 {
2357     return d->certs;
2358 }
2359 
2360 QList<CRL> CertificateCollection::crls() const
2361 {
2362     return d->crls;
2363 }
2364 
2365 void CertificateCollection::append(const CertificateCollection &other)
2366 {
2367     d->certs += other.d->certs;
2368     d->crls += other.d->crls;
2369 }
2370 
2371 CertificateCollection CertificateCollection::operator+(const CertificateCollection &other) const
2372 {
2373     CertificateCollection c = *this;
2374     c.append(other);
2375     return c;
2376 }
2377 
2378 CertificateCollection &CertificateCollection::operator+=(const CertificateCollection &other)
2379 {
2380     append(other);
2381     return *this;
2382 }
2383 
2384 bool CertificateCollection::canUsePKCS7(const QString &provider)
2385 {
2386     return isSupported("certcollection", provider);
2387 }
2388 
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 
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
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
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 //----------------------------------------------------------------------------
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 
2508 CertificateAuthority::CertificateAuthority(const CertificateAuthority &from)
2509     : Algorithm(from)
2510 {
2511 }
2512 
2513 CertificateAuthority::~CertificateAuthority()
2514 {
2515 }
2516 
2517 CertificateAuthority &CertificateAuthority::operator=(const CertificateAuthority &from)
2518 {
2519     Algorithm::operator=(from);
2520     return *this;
2521 }
2522 
2523 Certificate CertificateAuthority::certificate() const
2524 {
2525     Certificate c;
2526     c.change(static_cast<const CAContext *>(context())->certificate());
2527     return c;
2528 }
2529 
2530 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 
2540 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 
2549 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 
2570 KeyBundle::KeyBundle()
2571     : d(new Private)
2572 {
2573 }
2574 
2575 KeyBundle::KeyBundle(const QString &fileName, const SecureArray &passphrase)
2576     : d(new Private)
2577 {
2578     *this = fromFile(fileName, passphrase, nullptr, QString());
2579 }
2580 
2581 KeyBundle::KeyBundle(const KeyBundle &from)
2582     : d(from.d)
2583 {
2584 }
2585 
2586 KeyBundle::~KeyBundle()
2587 {
2588 }
2589 
2590 KeyBundle &KeyBundle::operator=(const KeyBundle &from)
2591 {
2592     d = from.d;
2593     return *this;
2594 }
2595 
2596 bool KeyBundle::isNull() const
2597 {
2598     return d->chain.isEmpty();
2599 }
2600 
2601 QString KeyBundle::name() const
2602 {
2603     return d->name;
2604 }
2605 
2606 CertificateChain KeyBundle::certificateChain() const
2607 {
2608     return d->chain;
2609 }
2610 
2611 PrivateKey KeyBundle::privateKey() const
2612 {
2613     return d->key;
2614 }
2615 
2616 void KeyBundle::setName(const QString &s)
2617 {
2618     d->name = s;
2619 }
2620 
2621 void KeyBundle::setCertificateChainAndKey(const CertificateChain &c, const PrivateKey &key)
2622 {
2623     d->chain = c;
2624     d->key   = key;
2625 }
2626 
2627 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 
2641 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
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 
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 //----------------------------------------------------------------------------
2676 PGPKey::PGPKey()
2677 {
2678 }
2679 
2680 PGPKey::PGPKey(const QString &fileName)
2681 {
2682     *this = fromFile(fileName, nullptr, QString());
2683 }
2684 
2685 PGPKey::PGPKey(const PGPKey &from)
2686     : Algorithm(from)
2687 {
2688 }
2689 
2690 PGPKey::~PGPKey()
2691 {
2692 }
2693 
2694 PGPKey &PGPKey::operator=(const PGPKey &from)
2695 {
2696     Algorithm::operator=(from);
2697     return *this;
2698 }
2699 
2700 bool PGPKey::isNull() const
2701 {
2702     return (!context() ? true : false);
2703 }
2704 
2705 QString PGPKey::keyId() const
2706 {
2707     return static_cast<const PGPKeyContext *>(context())->props()->keyId;
2708 }
2709 
2710 QString PGPKey::primaryUserId() const
2711 {
2712     return static_cast<const PGPKeyContext *>(context())->props()->userIds.first();
2713 }
2714 
2715 QStringList PGPKey::userIds() const
2716 {
2717     return static_cast<const PGPKeyContext *>(context())->props()->userIds;
2718 }
2719 
2720 bool PGPKey::isSecret() const
2721 {
2722     return static_cast<const PGPKeyContext *>(context())->props()->isSecret;
2723 }
2724 
2725 QDateTime PGPKey::creationDate() const
2726 {
2727     return static_cast<const PGPKeyContext *>(context())->props()->creationDate;
2728 }
2729 
2730 QDateTime PGPKey::expirationDate() const
2731 {
2732     return static_cast<const PGPKeyContext *>(context())->props()->expirationDate;
2733 }
2734 
2735 QString PGPKey::fingerprint() const
2736 {
2737     return static_cast<const PGPKeyContext *>(context())->props()->fingerprint;
2738 }
2739 
2740 bool PGPKey::inKeyring() const
2741 {
2742     return static_cast<const PGPKeyContext *>(context())->props()->inKeyring;
2743 }
2744 
2745 bool PGPKey::isTrusted() const
2746 {
2747     return static_cast<const PGPKeyContext *>(context())->props()->isTrusted;
2748 }
2749 
2750 QByteArray PGPKey::toArray() const
2751 {
2752     return static_cast<const PGPKeyContext *>(context())->toBinary();
2753 }
2754 
2755 QString PGPKey::toString() const
2756 {
2757     return static_cast<const PGPKeyContext *>(context())->toAscii();
2758 }
2759 
2760 bool PGPKey::toFile(const QString &fileName) const
2761 {
2762     return stringToFile(fileName, toString());
2763 }
2764 
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 
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 
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 
2840     KeyLoaderThread(QObject *parent = nullptr)
2841         : QThread(parent)
2842     {
2843     }
2844 
2845 protected:
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 
2872     Private(KeyLoader *_q)
2873         : QObject(_q)
2874         , q(_q)
2875     {
2876         active = false;
2877     }
2878 
2879     void reset()
2880     {
2881         in  = KeyLoaderThread::In();
2882         out = KeyLoaderThread::Out();
2883     }
2884 
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:
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 
2907 KeyLoader::KeyLoader(QObject *parent)
2908     : QObject(parent)
2909 {
2910     d = new Private(this);
2911 }
2912 
2913 KeyLoader::~KeyLoader()
2914 {
2915     delete d;
2916 }
2917 
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 
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 
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 
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 
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 
2978 ConvertResult KeyLoader::convertResult() const
2979 {
2980     return d->out.convertResult;
2981 }
2982 
2983 PrivateKey KeyLoader::privateKey() const
2984 {
2985     return d->out.privateKey;
2986 }
2987 
2988 KeyBundle KeyLoader::keyBundle() const
2989 {
2990     return d->out.keyBundle;
2991 }
2992 
2993 }
2994 
2995 #include "qca_cert.moc"