File indexing completed on 2024-12-01 04:21:58
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 ¬ValidAfter) const 2531 { 2532 Certificate c; 2533 CertContext *cc = static_cast<const CAContext *>(context())->signRequest( 2534 *(static_cast<const CSRContext *>(req.context())), notValidAfter); 2535 if (cc) 2536 c.change(cc); 2537 return c; 2538 } 2539 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"