File indexing completed on 2024-04-21 14:56:09

0001 /* This file is part of the KDE project
0002  *
0003  * Copyright (C) 2000-2003 George Staikos <staikos@kde.org>
0004  *               2008 Richard Hartmann <richih-kde@net.in.tum.de>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "ksslcertificate.h"
0023 
0024 #include <ksslconfig.h> // KSSL_HAVE_SSL
0025 
0026 #include <unistd.h>
0027 #include <QString>
0028 #include <QStringList>
0029 #include <QFile>
0030 #include <QStandardPaths>
0031 #include <QDate>
0032 #include <QDebug>
0033 #include <QDataStream>
0034 #include <qplatformdefs.h>
0035 #include <qtemporaryfile.h>
0036 
0037 #include "ksslcertchain.h"
0038 #include "ksslutils.h"
0039 
0040 #include <klocalizedstring.h>
0041 
0042 #include <sys/types.h>
0043 
0044 #include <config-kdelibs4support.h> // HAVE_SYS_STAT_H
0045 
0046 #if HAVE_SYS_STAT_H
0047 #include <sys/stat.h>
0048 #endif
0049 
0050 // this hack provided by Malte Starostik to avoid glibc/openssl bug
0051 // on some systems
0052 #if KSSL_HAVE_SSL
0053 #define crypt _openssl_crypt
0054 #include <openssl/ssl.h>
0055 #include <openssl/x509.h>
0056 #include <openssl/x509v3.h>
0057 #include <openssl/x509_vfy.h>
0058 #include <openssl/pem.h>
0059 #undef crypt
0060 #endif
0061 
0062 #include <kopenssl.h>
0063 #include "ksslx509v3.h"
0064 
0065 static const char hv[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
0066 
0067 class KSSLCertificatePrivate
0068 {
0069 public:
0070     KSSLCertificatePrivate()
0071     {
0072         kossl = KOSSL::self();
0073         _lastPurpose = KSSLCertificate::None;
0074     }
0075 
0076     ~KSSLCertificatePrivate()
0077     {
0078     }
0079 
0080     KSSLCertificate::KSSLValidation m_stateCache;
0081     bool m_stateCached;
0082 #if KSSL_HAVE_SSL
0083     X509 *m_cert;
0084 #endif
0085     KOSSL *kossl;
0086     KSSLCertChain _chain;
0087     KSSLX509V3 _extensions;
0088     KSSLCertificate::KSSLPurpose _lastPurpose;
0089 };
0090 
0091 KSSLCertificate::KSSLCertificate()
0092 {
0093     d = new KSSLCertificatePrivate;
0094     d->m_stateCached = false;
0095 #if KSSL_HAVE_SSL
0096     d->m_cert = nullptr;
0097 #endif
0098 }
0099 
0100 KSSLCertificate::KSSLCertificate(const KSSLCertificate &x)
0101 {
0102     d = new KSSLCertificatePrivate;
0103     d->m_stateCached = false;
0104 #if KSSL_HAVE_SSL
0105     d->m_cert = nullptr;
0106     setCert(KOSSL::self()->X509_dup(const_cast<KSSLCertificate &>(x).getCert()));
0107     KSSLCertChain *c = x.d->_chain.replicate();
0108     setChain(c->rawChain());
0109     delete c;
0110 #endif
0111 }
0112 
0113 KSSLCertificate::~KSSLCertificate()
0114 {
0115 #if KSSL_HAVE_SSL
0116     if (d->m_cert) {
0117         d->kossl->X509_free(d->m_cert);
0118     }
0119 #endif
0120     delete d;
0121 }
0122 
0123 KSSLCertChain &KSSLCertificate::chain()
0124 {
0125     return d->_chain;
0126 }
0127 
0128 KSSLCertificate *KSSLCertificate::fromX509(X509 *x5)
0129 {
0130     KSSLCertificate *n = nullptr;
0131 #if KSSL_HAVE_SSL
0132     if (x5) {
0133         n = new KSSLCertificate;
0134         n->setCert(KOSSL::self()->X509_dup(x5));
0135     }
0136 #endif
0137     return n;
0138 }
0139 
0140 KSSLCertificate *KSSLCertificate::fromString(const QByteArray &cert)
0141 {
0142     KSSLCertificate *n = nullptr;
0143 #if KSSL_HAVE_SSL
0144     if (cert.isEmpty()) {
0145         return nullptr;
0146     }
0147 
0148     QByteArray qba = QByteArray::fromBase64(cert);
0149     unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
0150     X509 *x5c = KOSSL::self()->d2i_X509(nullptr, &qbap, qba.size());
0151     if (!x5c) {
0152         return nullptr;
0153     }
0154 
0155     n = new KSSLCertificate;
0156     n->setCert(x5c);
0157 #endif
0158     return n;
0159 }
0160 
0161 QString KSSLCertificate::getSubject() const
0162 {
0163     QString rc = "";
0164 
0165 #if KSSL_HAVE_SSL
0166     char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_subject_name(d->m_cert), nullptr, 0);
0167     if (!t) {
0168         return rc;
0169     }
0170     rc = t;
0171     d->kossl->OPENSSL_free(t);
0172 #endif
0173     return rc;
0174 }
0175 
0176 QString KSSLCertificate::getSerialNumber() const
0177 {
0178     QString rc = "";
0179 
0180 #if KSSL_HAVE_SSL
0181     ASN1_INTEGER *aint = d->kossl->X509_get_serialNumber(d->m_cert);
0182     if (aint) {
0183         rc = ASN1_INTEGER_QString(aint);
0184         // d->kossl->ASN1_INTEGER_free(aint);   this makes the sig test fail
0185     }
0186 #endif
0187     return rc;
0188 }
0189 
0190 QString KSSLCertificate::getSignatureText() const
0191 {
0192     QString rc = "";
0193 
0194 #if KSSL_HAVE_SSL
0195     char *s;
0196     int n, i;
0197 
0198     const X509_ALGOR *algor;
0199     const ASN1_BIT_STRING *sig;
0200     d->kossl->X509_get0_signature(&sig, &algor, d->m_cert);
0201     i = d->kossl->OBJ_obj2nid(algor->algorithm);
0202     rc = i18n("Signature Algorithm: ");
0203     rc += (i == NID_undef) ? i18n("Unknown") : QString(d->kossl->OBJ_nid2ln(i));
0204 
0205     rc += '\n';
0206     rc += i18n("Signature Contents:");
0207     n = sig->length;
0208     s = (char *)sig->data;
0209     for (i = 0; i < n; ++i) {
0210         if (i % 20 != 0) {
0211             rc += ':';
0212         } else {
0213             rc += '\n';
0214         }
0215         rc.append(QChar(hv[(s[i] & 0xf0) >> 4]));
0216         rc.append(QChar(hv[s[i] & 0x0f]));
0217     }
0218 
0219 #endif
0220 
0221     return rc;
0222 }
0223 
0224 void KSSLCertificate::getEmails(QStringList &to) const
0225 {
0226     to.clear();
0227 #if KSSL_HAVE_SSL
0228     if (!d->m_cert) {
0229         return;
0230     }
0231 
0232     STACK *s = d->kossl->X509_get1_email(d->m_cert);
0233     const int size = d->kossl->OPENSSL_sk_num(s);
0234     if (s) {
0235         for (int n = 0; n < size; n++) {
0236             to.append(d->kossl->OPENSSL_sk_value(s, n));
0237         }
0238         d->kossl->X509_email_free(s);
0239     }
0240 #endif
0241 }
0242 
0243 QString KSSLCertificate::getKDEKey() const
0244 {
0245     return getSubject() + " (" + getMD5DigestText() + ')';
0246 }
0247 
0248 QString KSSLCertificate::getMD5DigestFromKDEKey(const QString &k)
0249 {
0250     QString rc;
0251     int pos = k.lastIndexOf('(');
0252     if (pos != -1) {
0253         unsigned int len = k.length();
0254         if (k.at(len - 1) == ')') {
0255             rc = k.mid(pos + 1, len - pos - 2);
0256         }
0257     }
0258     return rc;
0259 }
0260 
0261 QString KSSLCertificate::getMD5DigestText() const
0262 {
0263     QString rc = "";
0264 
0265 #if KSSL_HAVE_SSL
0266     unsigned int n;
0267     unsigned char md[EVP_MAX_MD_SIZE];
0268 
0269     if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) {
0270         return rc;
0271     }
0272 
0273     for (unsigned int j = 0; j < n; j++) {
0274         if (j > 0) {
0275             rc += ':';
0276         }
0277         rc.append(QChar(hv[(md[j] & 0xf0) >> 4]));
0278         rc.append(QChar(hv[md[j] & 0x0f]));
0279     }
0280 
0281 #endif
0282 
0283     return rc;
0284 }
0285 
0286 QString KSSLCertificate::getMD5Digest() const
0287 {
0288     QString rc = "";
0289 
0290 #if KSSL_HAVE_SSL
0291     unsigned int n;
0292     unsigned char md[EVP_MAX_MD_SIZE];
0293 
0294     if (!d->kossl->X509_digest(d->m_cert, d->kossl->EVP_md5(), md, &n)) {
0295         return rc;
0296     }
0297 
0298     for (unsigned int j = 0; j < n; j++) {
0299         rc.append(QLatin1Char(hv[(md[j] & 0xf0) >> 4]));
0300         rc.append(QLatin1Char(hv[md[j] & 0x0f]));
0301     }
0302 
0303 #endif
0304 
0305     return rc;
0306 }
0307 
0308 QString KSSLCertificate::getKeyType() const
0309 {
0310     QString rc = "";
0311 
0312 #if KSSL_HAVE_SSL
0313     EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
0314     if (pkey) {
0315 #ifndef NO_RSA
0316         if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
0317             rc = "RSA";
0318         } else
0319 #endif
0320 #ifndef NO_DSA
0321             if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_DSA) {
0322                 rc = "DSA";
0323             } else
0324 #endif
0325                 rc = "Unknown";
0326         d->kossl->EVP_PKEY_free(pkey);
0327     }
0328 #endif
0329 
0330     return rc;
0331 }
0332 
0333 QString KSSLCertificate::getPublicKeyText() const
0334 {
0335     QString rc = "";
0336     char *x = nullptr;
0337 
0338 #if KSSL_HAVE_SSL
0339     EVP_PKEY *pkey = d->kossl->X509_get_pubkey(d->m_cert);
0340     if (pkey) {
0341         rc = i18nc("Unknown", "Unknown key algorithm");
0342 #ifndef NO_RSA
0343         if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
0344             const BIGNUM *n, *e;
0345             d->kossl->RSA_get0_key(d->kossl->EVP_PKEY_get0_RSA(pkey), &n, &e, nullptr);
0346             x = d->kossl->BN_bn2hex(n);
0347             rc = i18n("Key type: RSA (%1 bit)", strlen(x) * 4) + '\n';
0348 
0349             rc += i18n("Modulus: ");
0350             for (unsigned int i = 0; i < strlen(x); i++) {
0351                 if (i % 40 != 0 && i % 2 == 0) {
0352                     rc += ':';
0353                 } else if (i % 40 == 0) {
0354                     rc += '\n';
0355                 }
0356                 rc += x[i];
0357             }
0358             rc += '\n';
0359             d->kossl->OPENSSL_free(x);
0360 
0361             x = d->kossl->BN_bn2hex(e);
0362             rc += i18n("Exponent: 0x") + QLatin1String(x) +
0363                   QLatin1String("\n");
0364             d->kossl->OPENSSL_free(x);
0365         }
0366 #endif
0367 #ifndef NO_DSA
0368         if (d->kossl->EVP_PKEY_base_id(pkey) == EVP_PKEY_DSA) {
0369             auto dsa = d->kossl->EVP_PKEY_get0_DSA(pkey);
0370             const BIGNUM *p, *q, *g;
0371             d->kossl->DSA_get0_pqg(dsa, &p, &q, &g);
0372             x = d->kossl->BN_bn2hex(p);
0373             // hack - this may not be always accurate
0374             rc = i18n("Key type: DSA (%1 bit)", strlen(x) * 4) + '\n';
0375 
0376             rc += i18n("Prime: ");
0377             for (unsigned int i = 0; i < strlen(x); i++) {
0378                 if (i % 40 != 0 && i % 2 == 0) {
0379                     rc += ':';
0380                 } else if (i % 40 == 0) {
0381                     rc += '\n';
0382                 }
0383                 rc += x[i];
0384             }
0385             rc += '\n';
0386             d->kossl->OPENSSL_free(x);
0387 
0388             x = d->kossl->BN_bn2hex(q);
0389             rc += i18n("160 bit prime factor: ");
0390             for (unsigned int i = 0; i < strlen(x); i++) {
0391                 if (i % 40 != 0 && i % 2 == 0) {
0392                     rc += ':';
0393                 } else if (i % 40 == 0) {
0394                     rc += '\n';
0395                 }
0396                 rc += x[i];
0397             }
0398             rc += '\n';
0399             d->kossl->OPENSSL_free(x);
0400 
0401             x = d->kossl->BN_bn2hex(g);
0402             rc += QString("g: ");
0403             for (unsigned int i = 0; i < strlen(x); i++) {
0404                 if (i % 40 != 0 && i % 2 == 0) {
0405                     rc += ':';
0406                 } else if (i % 40 == 0) {
0407                     rc += '\n';
0408                 }
0409                 rc += x[i];
0410             }
0411             rc += '\n';
0412             d->kossl->OPENSSL_free(x);
0413 
0414             const BIGNUM *pub_key;
0415             d->kossl->DSA_get0_key(dsa, &pub_key, nullptr);
0416             x = d->kossl->BN_bn2hex(pub_key);
0417             rc += i18n("Public key: ");
0418             for (unsigned int i = 0; i < strlen(x); i++) {
0419                 if (i % 40 != 0 && i % 2 == 0) {
0420                     rc += ':';
0421                 } else if (i % 40 == 0) {
0422                     rc += '\n';
0423                 }
0424                 rc += x[i];
0425             }
0426             rc += '\n';
0427             d->kossl->OPENSSL_free(x);
0428         }
0429 #endif
0430         d->kossl->EVP_PKEY_free(pkey);
0431     }
0432 #endif
0433 
0434     return rc;
0435 }
0436 
0437 QString KSSLCertificate::getIssuer() const
0438 {
0439     QString rc = "";
0440 
0441 #if KSSL_HAVE_SSL
0442     char *t = d->kossl->X509_NAME_oneline(d->kossl->X509_get_issuer_name(d->m_cert), nullptr, 0);
0443 
0444     if (!t) {
0445         return rc;
0446     }
0447 
0448     rc = t;
0449     d->kossl->OPENSSL_free(t);
0450 #endif
0451 
0452     return rc;
0453 }
0454 
0455 void KSSLCertificate::setChain(void *c)
0456 {
0457 #if KSSL_HAVE_SSL
0458     d->_chain.setChain(c);
0459 #endif
0460     d->m_stateCached = false;
0461     d->m_stateCache = KSSLCertificate::Unknown;
0462 }
0463 
0464 void KSSLCertificate::setCert(X509 *c)
0465 {
0466 #if KSSL_HAVE_SSL
0467     d->m_cert = c;
0468     if (c) {
0469         d->_extensions.flags = 0;
0470         d->kossl->X509_check_purpose(c, -1, 0);    // setup the fields (!!)
0471 
0472 #if 0
0473         qDebug() << "---------------- Certificate ------------------";
0474         qDebug() << getSubject();
0475 #endif
0476 
0477         for (int j = 0; j < d->kossl->X509_PURPOSE_get_count(); j++) {
0478             X509_PURPOSE *ptmp = d->kossl->X509_PURPOSE_get0(j);
0479             int id = d->kossl->X509_PURPOSE_get_id(ptmp);
0480             for (int ca = 0; ca < 2; ca++) {
0481                 int idret = d->kossl->X509_check_purpose(c, id, ca);
0482                 if (idret == 1 || idret == 2) {   // have it
0483                     // qDebug() << "PURPOSE: " << id << (ca?" CA":"");
0484                     if (!ca) {
0485                         d->_extensions.flags |= (1L << (id - 1));
0486                     } else {
0487                         d->_extensions.flags |= (1L << (16 + id - 1));
0488                     }
0489                 } else {
0490                     if (!ca) {
0491                         d->_extensions.flags &= ~(1L << (id - 1));
0492                     } else {
0493                         d->_extensions.flags &= ~(1L << (16 + id - 1));
0494                     }
0495                 }
0496             }
0497         }
0498 
0499 #if 0
0500         qDebug() << "flags: " << QString::number(c->ex_flags, 2)
0501                  << "\nkeyusage: " << QString::number(c->ex_kusage, 2)
0502                  << "\nxkeyusage: " << QString::number(c->ex_xkusage, 2)
0503                  << "\nnscert: " << QString::number(c->ex_nscert, 2);
0504         if (c->ex_flags & EXFLAG_KUSAGE) {
0505             qDebug() << "     --- Key Usage extensions found";
0506         } else {
0507             qDebug() << "     --- Key Usage extensions NOT found";
0508         }
0509 
0510         if (c->ex_flags & EXFLAG_XKUSAGE) {
0511             qDebug() << "     --- Extended key usage extensions found";
0512         } else {
0513             qDebug() << "     --- Extended key usage extensions NOT found";
0514         }
0515 
0516         if (c->ex_flags & EXFLAG_NSCERT) {
0517             qDebug() << "     --- NS extensions found";
0518         } else {
0519             qDebug() << "     --- NS extensions NOT found";
0520         }
0521 
0522         if (d->_extensions.certTypeSSLCA()) {
0523             qDebug() << "NOTE: this is an SSL CA file.";
0524         } else {
0525             qDebug() << "NOTE: this is NOT an SSL CA file.";
0526         }
0527 
0528         if (d->_extensions.certTypeEmailCA()) {
0529             qDebug() << "NOTE: this is an EMAIL CA file.";
0530         } else {
0531             qDebug() << "NOTE: this is NOT an EMAIL CA file.";
0532         }
0533 
0534         if (d->_extensions.certTypeCodeCA()) {
0535             qDebug() << "NOTE: this is a CODE CA file.";
0536         } else {
0537             qDebug() << "NOTE: this is NOT a CODE CA file.";
0538         }
0539 
0540         if (d->_extensions.certTypeSSLClient()) {
0541             qDebug() << "NOTE: this is an SSL client.";
0542         } else {
0543             qDebug() << "NOTE: this is NOT an SSL client.";
0544         }
0545 
0546         if (d->_extensions.certTypeSSLServer()) {
0547             qDebug() << "NOTE: this is an SSL server.";
0548         } else {
0549             qDebug() << "NOTE: this is NOT an SSL server.";
0550         }
0551 
0552         if (d->_extensions.certTypeNSSSLServer()) {
0553             qDebug() << "NOTE: this is a NETSCAPE SSL server.";
0554         } else {
0555             qDebug() << "NOTE: this is NOT a NETSCAPE SSL server.";
0556         }
0557 
0558         if (d->_extensions.certTypeSMIME()) {
0559             qDebug() << "NOTE: this is an SMIME certificate.";
0560         } else {
0561             qDebug() << "NOTE: this is NOT an SMIME certificate.";
0562         }
0563 
0564         if (d->_extensions.certTypeSMIMEEncrypt()) {
0565             qDebug() << "NOTE: this is an SMIME encrypt cert.";
0566         } else {
0567             qDebug() << "NOTE: this is NOT an SMIME encrypt cert.";
0568         }
0569 
0570         if (d->_extensions.certTypeSMIMESign()) {
0571             qDebug() << "NOTE: this is an SMIME sign cert.";
0572         } else {
0573             qDebug() << "NOTE: this is NOT an SMIME sign cert.";
0574         }
0575 
0576         if (d->_extensions.certTypeCRLSign()) {
0577             qDebug() << "NOTE: this is a CRL signer.";
0578         } else {
0579             qDebug() << "NOTE: this is NOT a CRL signer.";
0580         }
0581 
0582         qDebug() << "-----------------------------------------------";
0583 #endif
0584     }
0585 #endif
0586     d->m_stateCached = false;
0587     d->m_stateCache = KSSLCertificate::Unknown;
0588 }
0589 
0590 X509 *KSSLCertificate::getCert()
0591 {
0592 #if KSSL_HAVE_SSL
0593     return d->m_cert;
0594 #endif
0595     return nullptr;
0596 }
0597 
0598 // pull in the callback.  It's common across multiple files but we want
0599 // it to be hidden.
0600 
0601 #include "ksslcallback.c"
0602 
0603 bool KSSLCertificate::isValid(KSSLCertificate::KSSLPurpose p)
0604 {
0605     return (validate(p) == KSSLCertificate::Ok);
0606 }
0607 
0608 bool KSSLCertificate::isValid()
0609 {
0610     return isValid(KSSLCertificate::SSLServer);
0611 }
0612 
0613 int KSSLCertificate::purposeToOpenSSL(KSSLCertificate::KSSLPurpose p) const
0614 {
0615     int rc = 0;
0616 #if KSSL_HAVE_SSL
0617     if (p == KSSLCertificate::SSLServer) {
0618         rc = X509_PURPOSE_SSL_SERVER;
0619     } else if (p == KSSLCertificate::SSLClient) {
0620         rc = X509_PURPOSE_SSL_CLIENT;
0621     } else if (p == KSSLCertificate::SMIMEEncrypt) {
0622         rc = X509_PURPOSE_SMIME_ENCRYPT;
0623     } else if (p == KSSLCertificate::SMIMESign) {
0624         rc = X509_PURPOSE_SMIME_SIGN;
0625     } else if (p == KSSLCertificate::Any) {
0626         rc = X509_PURPOSE_ANY;
0627     }
0628 #endif
0629     return rc;
0630 }
0631 
0632 // For backward compatibility
0633 KSSLCertificate::KSSLValidation KSSLCertificate::validate()
0634 {
0635     return validate(KSSLCertificate::SSLServer);
0636 }
0637 
0638 KSSLCertificate::KSSLValidation KSSLCertificate::validate(KSSLCertificate::KSSLPurpose purpose)
0639 {
0640     KSSLValidationList result = validateVerbose(purpose);
0641     if (result.isEmpty()) {
0642         return KSSLCertificate::Ok;
0643     } else {
0644         return result.first();
0645     }
0646 }
0647 
0648 //
0649 // See apps/verify.c in OpenSSL for the source of most of this logic.
0650 //
0651 
0652 // CRL files?  we don't do that yet
0653 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose)
0654 {
0655     return validateVerbose(purpose, nullptr);
0656 }
0657 
0658 KSSLCertificate::KSSLValidationList KSSLCertificate::validateVerbose(KSSLCertificate::KSSLPurpose purpose, KSSLCertificate *ca)
0659 {
0660     KSSLValidationList errors;
0661     if (ca || (d->_lastPurpose != purpose)) {
0662         d->m_stateCached = false;
0663     }
0664 
0665     if (!d->m_stateCached) {
0666         d->_lastPurpose = purpose;
0667     }
0668 
0669 #if KSSL_HAVE_SSL
0670     X509_STORE *certStore;
0671     X509_LOOKUP *certLookup;
0672     X509_STORE_CTX *certStoreCTX;
0673     int rc = 0;
0674 
0675     if (!d->m_cert) {
0676         errors << KSSLCertificate::Unknown;
0677         return errors;
0678     }
0679 
0680     if (d->m_stateCached) {
0681         errors << d->m_stateCache;
0682         return errors;
0683     }
0684 
0685     const QStringList qsl = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kf5/kssl", QStandardPaths::LocateDirectory);
0686 
0687     if (qsl.isEmpty()) {
0688         errors << KSSLCertificate::NoCARoot;
0689         return errors;
0690     }
0691 
0692     KSSLCertificate::KSSLValidation ksslv = Unknown;
0693 
0694     for (QStringList::ConstIterator j = qsl.begin(); j != qsl.end(); ++j) {
0695         QString _j = (*j) + "ca-bundle.crt";
0696         if (!QFile::exists(_j)) {
0697             continue;
0698         }
0699 
0700         certStore = d->kossl->X509_STORE_new();
0701         if (!certStore) {
0702             errors << KSSLCertificate::Unknown;
0703             return errors;
0704         }
0705 
0706         d->kossl->X509_STORE_set_verify_cb(certStore, X509Callback);
0707 
0708         certLookup = d->kossl->X509_STORE_add_lookup(certStore, d->kossl->X509_LOOKUP_file());
0709         if (!certLookup) {
0710             ksslv = KSSLCertificate::Unknown;
0711             d->kossl->X509_STORE_free(certStore);
0712             continue;
0713         }
0714 
0715         if (!d->kossl->X509_LOOKUP_load_file(certLookup, _j.toLatin1().constData(), X509_FILETYPE_PEM)) {
0716             // error accessing directory and loading pems
0717             qDebug() << "KSSL couldn't read CA root: " << _j;
0718             ksslv = KSSLCertificate::ErrorReadingRoot;
0719             d->kossl->X509_STORE_free(certStore);
0720             continue;
0721         }
0722 
0723         // This is the checking code
0724         certStoreCTX = d->kossl->X509_STORE_CTX_new();
0725 
0726         // this is a bad error - could mean no free memory.
0727         // This may be the wrong thing to do here
0728         if (!certStoreCTX) {
0729             qDebug() << "KSSL couldn't create an X509 store context.";
0730             d->kossl->X509_STORE_free(certStore);
0731             continue;
0732         }
0733 
0734         d->kossl->X509_STORE_CTX_init(certStoreCTX, certStore, d->m_cert, nullptr);
0735         if (d->_chain.isValid()) {
0736             d->kossl->X509_STORE_CTX_set_chain(certStoreCTX, (STACK_OF(X509) *)d->_chain.rawChain());
0737         }
0738 
0739         //qDebug() << "KSSL setting CRL..............";
0740         // int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
0741 
0742         d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX, purposeToOpenSSL(purpose));
0743 
0744         KSSL_X509CallBack_ca = ca ? ca->d->m_cert : nullptr;
0745         KSSL_X509CallBack_ca_found = false;
0746 
0747         d->kossl->X509_STORE_CTX_set_error(certStoreCTX, X509_V_OK);
0748         rc = d->kossl->X509_verify_cert(certStoreCTX);
0749         int errcode = d->kossl->X509_STORE_CTX_get_error(certStoreCTX);
0750         if (ca && !KSSL_X509CallBack_ca_found) {
0751             ksslv = KSSLCertificate::Irrelevant;
0752         } else {
0753             ksslv = processError(errcode);
0754         }
0755         // For servers, we can try NS_SSL_SERVER too
0756         if ((ksslv != KSSLCertificate::Ok) &&
0757                 (ksslv != KSSLCertificate::Irrelevant) &&
0758                 purpose == KSSLCertificate::SSLServer) {
0759             d->kossl->X509_STORE_CTX_set_purpose(certStoreCTX,
0760                                                  X509_PURPOSE_NS_SSL_SERVER);
0761 
0762             d->kossl->X509_STORE_CTX_set_error(certStoreCTX, X509_V_OK);
0763             rc = d->kossl->X509_verify_cert(certStoreCTX);
0764             errcode = d->kossl->X509_STORE_CTX_get_error(certStoreCTX);
0765             ksslv = processError(errcode);
0766         }
0767         d->kossl->X509_STORE_CTX_free(certStoreCTX);
0768         d->kossl->X509_STORE_free(certStore);
0769         // end of checking code
0770         //
0771 
0772         //qDebug() << "KSSL Validation procedure RC: "
0773         //        << rc << endl;
0774         //qDebug() << "KSSL Validation procedure errcode: "
0775         //        << errcode << endl;
0776         //qDebug() << "KSSL Validation procedure RESULTS: "
0777         //        << ksslv << endl;
0778 
0779         if (ksslv != NoCARoot && ksslv != InvalidCA && ksslv != GetIssuerCertFailed && ksslv != DecodeIssuerPublicKeyFailed && ksslv != GetIssuerCertLocallyFailed) {
0780             d->m_stateCached = true;
0781             d->m_stateCache = ksslv;
0782         }
0783         break;
0784     }
0785 
0786     if (ksslv != KSSLCertificate::Ok) {
0787         errors << ksslv;
0788     }
0789 #else
0790     errors << KSSLCertificate::NoSSL;
0791 #endif
0792     return errors;
0793 }
0794 
0795 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate()
0796 {
0797     return revalidate(KSSLCertificate::SSLServer);
0798 }
0799 
0800 KSSLCertificate::KSSLValidation KSSLCertificate::revalidate(KSSLCertificate::KSSLPurpose p)
0801 {
0802     d->m_stateCached = false;
0803     return validate(p);
0804 }
0805 
0806 KSSLCertificate::KSSLValidation KSSLCertificate::processError(int ec)
0807 {
0808     KSSLCertificate::KSSLValidation rc;
0809 
0810     rc = KSSLCertificate::Unknown;
0811 #if KSSL_HAVE_SSL
0812     switch (ec) {
0813 
0814     // see man 1 verify for a detailed listing of all error codes
0815 
0816     // error 0
0817     case X509_V_OK:
0818         rc = KSSLCertificate::Ok;
0819         break;
0820 
0821     // error 2
0822     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
0823         rc = KSSLCertificate::GetIssuerCertFailed;
0824         break;
0825 
0826     // error 3
0827     case X509_V_ERR_UNABLE_TO_GET_CRL:
0828         rc = KSSLCertificate::GetCRLFailed;
0829         break;
0830 
0831     // error 4
0832     case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
0833         rc = KSSLCertificate::DecryptCertificateSignatureFailed;
0834         break;
0835 
0836     // error 5
0837     case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
0838         rc = KSSLCertificate::DecryptCRLSignatureFailed;
0839         break;
0840 
0841     // error 6
0842     case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
0843         rc = KSSLCertificate::DecodeIssuerPublicKeyFailed;
0844         break;
0845 
0846     // error 7
0847     case X509_V_ERR_CERT_SIGNATURE_FAILURE:
0848         rc = KSSLCertificate::CertificateSignatureFailed;
0849         break;
0850 
0851     // error 8
0852     case X509_V_ERR_CRL_SIGNATURE_FAILURE:
0853         rc = KSSLCertificate::CRLSignatureFailed;
0854         break;
0855 
0856     // error 9
0857     case X509_V_ERR_CERT_NOT_YET_VALID:
0858         rc = KSSLCertificate::CertificateNotYetValid;
0859         break;
0860 
0861     // error 10
0862     case X509_V_ERR_CERT_HAS_EXPIRED:
0863         rc = KSSLCertificate::CertificateHasExpired;
0864         qDebug() << "KSSL apparently this is expired.  Not after:" << getNotAfter();
0865         break;
0866 
0867     // error 11
0868     case X509_V_ERR_CRL_NOT_YET_VALID:
0869         rc = KSSLCertificate::CRLNotYetValid;
0870         break;
0871 
0872     // error 12
0873     case X509_V_ERR_CRL_HAS_EXPIRED:
0874         rc = KSSLCertificate::CRLHasExpired;
0875         break;
0876 
0877     // error 13
0878     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
0879         rc = KSSLCertificate::CertificateFieldNotBeforeErroneous;
0880         break;
0881 
0882     // error 14
0883     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
0884         rc = KSSLCertificate::CertificateFieldNotAfterErroneous;
0885         break;
0886 
0887     // error 15 - unused as of OpenSSL 0.9.8g
0888     case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
0889         rc = KSSLCertificate::CRLFieldLastUpdateErroneous;
0890         break;
0891 
0892     // error 16 - unused as of OpenSSL 0.9.8g
0893     case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
0894         rc = KSSLCertificate::CRLFieldNextUpdateErroneous;
0895         break;
0896 
0897     // error 17
0898     case X509_V_ERR_OUT_OF_MEM:
0899         rc = KSSLCertificate::OutOfMemory;
0900         break;
0901 
0902     // error 18
0903     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
0904         rc = KSSLCertificate::SelfSigned;
0905         break;
0906 
0907     // error 19
0908     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
0909         rc = KSSLCertificate::SelfSignedInChain;
0910         break;
0911 
0912     // error 20
0913     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
0914         rc = KSSLCertificate::GetIssuerCertLocallyFailed;
0915         break;
0916 
0917     // error 21
0918     case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
0919         rc = KSSLCertificate::VerifyLeafSignatureFailed;
0920         break;
0921 
0922     // error 22 - unused as of OpenSSL 0.9.8g
0923     case X509_V_ERR_CERT_CHAIN_TOO_LONG:
0924         rc = KSSLCertificate::CertificateChainTooLong;
0925         break;
0926 
0927     // error 23 - unused as of OpenSSL 0.9.8g
0928     case X509_V_ERR_CERT_REVOKED:
0929         rc = KSSLCertificate::CertificateRevoked;
0930         break;
0931 
0932     // error 24
0933     case X509_V_ERR_INVALID_CA:
0934         rc = KSSLCertificate::InvalidCA;
0935         break;
0936 
0937     // error 25
0938     case X509_V_ERR_PATH_LENGTH_EXCEEDED:
0939         rc = KSSLCertificate::PathLengthExceeded;
0940         break;
0941 
0942     // error 26
0943     case X509_V_ERR_INVALID_PURPOSE:
0944         rc = KSSLCertificate::InvalidPurpose;
0945         break;
0946 
0947     // error 27
0948     case X509_V_ERR_CERT_UNTRUSTED:
0949         rc = KSSLCertificate::CertificateUntrusted;
0950         break;
0951 
0952     // error 28
0953     case X509_V_ERR_CERT_REJECTED:
0954         rc = KSSLCertificate::CertificateRejected;
0955         break;
0956 
0957     // error 29 - only used with -issuer_checks
0958     case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
0959         rc = KSSLCertificate::IssuerSubjectMismatched;
0960         break;
0961 
0962     // error 30 - only used with -issuer_checks
0963     case X509_V_ERR_AKID_SKID_MISMATCH:
0964         rc = KSSLCertificate::AuthAndSubjectKeyIDMismatched;
0965         break;
0966 
0967     // error 31 - only used with -issuer_checks
0968     case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
0969         rc = KSSLCertificate::AuthAndSubjectKeyIDAndNameMismatched;
0970         break;
0971 
0972     // error 32
0973     case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
0974         rc = KSSLCertificate::KeyMayNotSignCertificate;
0975         break;
0976 
0977     // error 50 - unused as of OpenSSL 0.9.8g
0978     case X509_V_ERR_APPLICATION_VERIFICATION:
0979         rc = KSSLCertificate::ApplicationVerificationFailed;
0980         break;
0981 
0982     default:
0983         rc = KSSLCertificate::Unknown;
0984         break;
0985     }
0986 
0987     d->m_stateCache = rc;
0988     d->m_stateCached = true;
0989 #endif
0990     return rc;
0991 }
0992 
0993 QString KSSLCertificate::getNotBefore() const
0994 {
0995 #if KSSL_HAVE_SSL
0996     return ASN1_UTCTIME_QString(d->kossl->X509_getm_notBefore(d->m_cert));
0997 #else
0998     return QString();
0999 #endif
1000 }
1001 
1002 QString KSSLCertificate::getNotAfter() const
1003 {
1004 #if KSSL_HAVE_SSL
1005     return ASN1_UTCTIME_QString(d->kossl->X509_getm_notAfter(d->m_cert));
1006 #else
1007     return QString();
1008 #endif
1009 }
1010 
1011 QDateTime KSSLCertificate::getQDTNotBefore() const
1012 {
1013 #if KSSL_HAVE_SSL
1014     return ASN1_UTCTIME_QDateTime(d->kossl->X509_getm_notBefore(d->m_cert), nullptr);
1015 #else
1016     return QDateTime::currentDateTime();
1017 #endif
1018 }
1019 
1020 QDateTime KSSLCertificate::getQDTNotAfter() const
1021 {
1022 #if KSSL_HAVE_SSL
1023     return ASN1_UTCTIME_QDateTime(d->kossl->X509_getm_notAfter(d->m_cert), nullptr);
1024 #else
1025     return QDateTime::currentDateTime();
1026 #endif
1027 }
1028 
1029 int operator==(KSSLCertificate &x, KSSLCertificate &y)
1030 {
1031 #if !KSSL_HAVE_SSL
1032     return 1;
1033 #else
1034     if (!KOSSL::self()->X509_cmp(x.getCert(), y.getCert())) {
1035         return 1;
1036     }
1037     return 0;
1038 #endif
1039 }
1040 
1041 KSSLCertificate *KSSLCertificate::replicate()
1042 {
1043     // The new certificate doesn't have the cached value.  It's probably
1044     // better this way.  We can't anticipate every reason for doing this.
1045     KSSLCertificate *newOne = new KSSLCertificate();
1046 #if KSSL_HAVE_SSL
1047     newOne->setCert(d->kossl->X509_dup(getCert()));
1048     KSSLCertChain *c = d->_chain.replicate();
1049     newOne->setChain(c->rawChain());
1050     delete c;
1051 #endif
1052     return newOne;
1053 }
1054 
1055 QString KSSLCertificate::toString()
1056 {
1057     return toDer().toBase64();
1058 }
1059 
1060 QString KSSLCertificate::verifyText(KSSLValidation x)
1061 {
1062     switch (x) {
1063     // messages for errors defined in verify(1)
1064     case KSSLCertificate::Ok:
1065         return i18n("The certificate is valid.");
1066     case KSSLCertificate::GetIssuerCertFailed:
1067         return i18n("Retrieval of the issuer certificate failed. This means the CA's (Certificate Authority) certificate can not be found.");
1068     case KSSLCertificate::GetCRLFailed:
1069         return i18n("Retrieval of the CRL (Certificate Revocation List) failed. This means the CA's (Certificate Authority) CRL can not be found.");
1070     case KSSLCertificate::DecryptCertificateSignatureFailed:
1071         return i18n("The decryption of the certificate's signature failed. This means it could not even be calculated as opposed to just not matching the expected result.");
1072     case KSSLCertificate::DecryptCRLSignatureFailed:
1073         return i18n("The decryption of the CRL's (Certificate Revocation List) signature failed. This means it could not even be calculated as opposed to just not matching the expected result.");
1074     case KSSLCertificate::DecodeIssuerPublicKeyFailed:
1075         return i18n("The decoding of the public key of the issuer failed. This means that the CA's (Certificate Authority) certificate can not be used to verify the certificate you wanted to use.");
1076     case KSSLCertificate::CertificateSignatureFailed:
1077         return i18n("The certificate's signature is invalid. This means that the certificate can not be verified.");
1078     case KSSLCertificate::CRLSignatureFailed:
1079         return i18n("The CRL's (Certificate Revocation List) signature is invalid. This means that the CRL can not be verified.");
1080     case KSSLCertificate::CertificateNotYetValid:
1081         return i18n("The certificate is not valid, yet.");
1082     case KSSLCertificate::CertificateHasExpired:
1083         return i18n("The certificate is not valid, any more.");
1084     case KSSLCertificate::CRLNotYetValid:
1085         return i18n("The CRL (Certificate Revocation List) is not valid, yet.");
1086     case KSSLCertificate::CRLHasExpired:
1087         return i18n("The CRL (Certificate Revocation List) is not valid, yet.");
1088     case KSSLCertificate::CertificateFieldNotBeforeErroneous:
1089         return i18n("The time format of the certificate's 'notBefore' field is invalid.");
1090     case KSSLCertificate::CertificateFieldNotAfterErroneous:
1091         return i18n("The time format of the certificate's 'notAfter' field is invalid.");
1092     case KSSLCertificate::CRLFieldLastUpdateErroneous:
1093         return i18n("The time format of the CRL's (Certificate Revocation List) 'lastUpdate' field is invalid.");
1094     case KSSLCertificate::CRLFieldNextUpdateErroneous:
1095         return i18n("The time format of the CRL's (Certificate Revocation List) 'nextUpdate' field is invalid.");
1096     case KSSLCertificate::OutOfMemory:
1097         return i18n("The OpenSSL process ran out of memory.");
1098     case KSSLCertificate::SelfSigned:
1099         return i18n("The certificate is self-signed and not in the list of trusted certificates. If you want to accept this certificate, import it into the list of trusted certificates.");
1100     case KSSLCertificate::SelfSignedChain:      // this is obsolete and kept around for backwards compatibility, only
1101     case KSSLCertificate::SelfSignedInChain:
1102         return i18n("The certificate is self-signed. While the trust chain could be built up, the root CA's (Certificate Authority) certificate can not be found.");
1103     case KSSLCertificate::GetIssuerCertLocallyFailed:
1104         return i18n("The CA's (Certificate Authority) certificate can not be found. Most likely, your trust chain is broken.");
1105     case KSSLCertificate::VerifyLeafSignatureFailed:
1106         return i18n("The certificate can not be verified as it is the only certificate in the trust chain and not self-signed. If you self-sign the certificate, make sure to import it into the list of trusted certificates.");
1107     case KSSLCertificate::CertificateChainTooLong:
1108         return i18n("The certificate chain is longer than the maximum depth specified.");
1109     case KSSLCertificate::Revoked:     // this is obsolete and kept around for backwards compatibility, only
1110     case KSSLCertificate::CertificateRevoked:
1111         return i18n("The certificate has been revoked.");
1112     case KSSLCertificate::InvalidCA:
1113         return i18n("The certificate's CA (Certificate Authority) is invalid.");
1114     case KSSLCertificate::PathLengthExceeded:
1115         return i18n("The length of the trust chain exceeded one of the CA's (Certificate Authority) 'pathlength' parameters, making all subsequent signatures invalid.");
1116     case KSSLCertificate::InvalidPurpose:
1117         return i18n("The certificate has not been signed for the purpose you tried to use it for. This means the CA (Certificate Authority) does not allow this usage.");
1118     case KSSLCertificate::Untrusted:     // this is obsolete and kept around for backwards compatibility, only
1119     case KSSLCertificate::CertificateUntrusted:
1120         return i18n("The root CA (Certificate Authority) is not trusted for the purpose you tried to use this certificate for.");
1121     case KSSLCertificate::Rejected:     // this is obsolete and kept around for backwards compatibility, only     // this is obsolete and kept around for backwards compatibility, onle
1122     case KSSLCertificate::CertificateRejected:
1123         return i18n("The root CA (Certificate Authority) has been marked to be rejected for the purpose you tried to use it for.");
1124     case KSSLCertificate::IssuerSubjectMismatched:
1125         return i18n("The certificate's CA (Certificate Authority) does not match the CA name of the certificate.");
1126     case KSSLCertificate::AuthAndSubjectKeyIDMismatched:
1127         return i18n("The CA (Certificate Authority) certificate's key ID does not match the key ID in the 'Issuer' section of the certificate you are trying to use.");
1128     case KSSLCertificate::AuthAndSubjectKeyIDAndNameMismatched:
1129         return i18n("The CA (Certificate Authority) certificate's key ID and name do not match the key ID and name in the 'Issuer' section of the certificate you are trying to use.");
1130     case KSSLCertificate::KeyMayNotSignCertificate:
1131         return i18n("The certificate's CA (Certificate Authority) is not allowed to sign certificates.");
1132     case KSSLCertificate::ApplicationVerificationFailed:
1133         return i18n("OpenSSL could not be verified.");
1134 
1135     // this is obsolete and kept around for backwards compatibility, only
1136     case KSSLCertificate::SignatureFailed:
1137         return i18n("The signature test for this certificate failed. This could mean that the signature of this certificate or any in its trust path are invalid, could not be decoded or that the CRL (Certificate Revocation List) could not be verified. If you see this message, please let the author of the software you are using know that he or she should use the new, more specific error messages.");
1138     case KSSLCertificate::Expired:
1139         return i18n("This certificate, any in its trust path or its CA's (Certificate Authority) CRL (Certificate Revocation List) is not valid. Any of them could not be valid yet or not valid any more. If you see this message, please let the author of the software you are using know that he or she should use the new, more specific error messages.");
1140     // continue 'useful' messages
1141 
1142     // other error messages
1143     case KSSLCertificate::ErrorReadingRoot:
1144     case KSSLCertificate::NoCARoot:
1145         return i18n("Certificate signing authority root files could not be found so the certificate is not verified.");
1146     case KSSLCertificate::NoSSL:
1147         return i18n("SSL support was not found.");
1148     case KSSLCertificate::PrivateKeyFailed:
1149         return i18n("Private key test failed.");
1150     case KSSLCertificate::InvalidHost:
1151         return i18n("The certificate has not been issued for this host.");
1152     case KSSLCertificate::Irrelevant:
1153         return i18n("This certificate is not relevant.");
1154     default:
1155         break;
1156     }
1157 
1158     return i18n("The certificate is invalid.");
1159 }
1160 
1161 QByteArray KSSLCertificate::toDer()
1162 {
1163     QByteArray qba;
1164 #if KSSL_HAVE_SSL
1165     int certlen = d->kossl->i2d_X509(getCert(), nullptr);
1166     if (certlen >= 0) {
1167         // These should technically be unsigned char * but it doesn't matter
1168         // for our purposes
1169         char *cert = new char[certlen];
1170         unsigned char *p = (unsigned char *)cert;
1171         // FIXME: return code!
1172         d->kossl->i2d_X509(getCert(), &p);
1173 
1174         // encode it into a QString
1175         qba = QByteArray(cert, certlen);
1176         delete[] cert;
1177     }
1178 #endif
1179     return qba;
1180 }
1181 
1182 QByteArray KSSLCertificate::toPem()
1183 {
1184     QByteArray qba;
1185     QString thecert = toString();
1186     const char *header = "-----BEGIN CERTIFICATE-----\n";
1187     const char *footer = "-----END CERTIFICATE-----\n";
1188 
1189     // We just do base64 on the ASN1
1190     //  64 character lines  (unpadded)
1191     unsigned int xx = thecert.length() - 1;
1192     for (unsigned int i = 0; i < xx / 64; i++) {
1193         thecert.insert(64 * (i + 1) + i, '\n');
1194     }
1195 
1196     thecert.prepend(header);
1197 
1198     if (thecert[thecert.length() - 1] != '\n') {
1199         thecert += '\n';
1200     }
1201 
1202     thecert.append(footer);
1203 
1204     qba = thecert.toLocal8Bit();
1205     return qba;
1206 }
1207 
1208 #define NETSCAPE_CERT_HDR     "certificate"
1209 
1210 #if KSSL_HAVE_SSL
1211 #if OPENSSL_VERSION_NUMBER < 0x00909000L
1212 
1213 typedef struct NETSCAPE_X509_st {
1214     ASN1_OCTET_STRING *header;
1215     X509 *cert;
1216 } NETSCAPE_X509;
1217 #endif
1218 #endif
1219 
1220 // what a piece of crap this is
1221 QByteArray KSSLCertificate::toNetscape()
1222 {
1223     QByteArray qba;
1224      // no equivalent in OpenSSL 1.1.0 (?), so behave as if we had no OpenSSL at all
1225 #if KSSL_HAVE_SSL && (OPENSSL_VERSION_NUMBER < 0x10100000L)
1226     NETSCAPE_X509 nx;
1227     ASN1_OCTET_STRING hdr;
1228     QTemporaryFile ktf;
1229     ktf.open();
1230     FILE *ktf_fs = QT_FOPEN(QFile::encodeName(ktf.fileName()).constData(), "r+");
1231 
1232     hdr.data = (unsigned char *)NETSCAPE_CERT_HDR;
1233     hdr.length = strlen(NETSCAPE_CERT_HDR);
1234     nx.header = &hdr;
1235     nx.cert = getCert();
1236 
1237     d->kossl->ASN1_item_i2d_fp(ktf_fs, (unsigned char *)&nx);
1238     fclose(ktf_fs);
1239 
1240     QFile qf(ktf.fileName());
1241     if (qf.open(QIODevice::ReadOnly)) {
1242         qba = qf.readAll();
1243     }
1244 #endif
1245     return qba;
1246 }
1247 
1248 QString KSSLCertificate::toText()
1249 {
1250     QString text;
1251 #if KSSL_HAVE_SSL
1252     QTemporaryFile ktf;
1253     ktf.open();
1254     FILE *ktf_fs = QT_FOPEN(QFile::encodeName(ktf.fileName()).constData(), "r+");
1255 
1256     d->kossl->X509_print(ktf_fs, getCert());
1257     fclose(ktf_fs);
1258 
1259     QFile qf(ktf.fileName());
1260     if (!qf.open(QIODevice::ReadOnly)) {
1261         return text;
1262     }
1263     char *buf = new char[qf.size() + 1];
1264     qf.read(buf, qf.size());
1265     buf[qf.size()] = 0;
1266     text = buf;
1267     delete[] buf;
1268     qf.close();
1269 #endif
1270     return text;
1271 }
1272 
1273 bool KSSLCertificate::setCert(const QString &cert)
1274 {
1275 #if KSSL_HAVE_SSL
1276     QByteArray qba, qbb = cert.toLocal8Bit();
1277     qba = QByteArray::fromBase64(qbb);
1278     unsigned char *qbap = reinterpret_cast<unsigned char *>(qba.data());
1279     X509 *x5c = KOSSL::self()->d2i_X509(nullptr, &qbap, qba.size());
1280     if (x5c) {
1281         setCert(x5c);
1282         return true;
1283     }
1284 #endif
1285     return false;
1286 }
1287 
1288 KSSLX509V3 &KSSLCertificate::x509V3Extensions()
1289 {
1290     return d->_extensions;
1291 }
1292 
1293 bool KSSLCertificate::isSigner()
1294 {
1295     return d->_extensions.certTypeCA();
1296 }
1297 
1298 QStringList KSSLCertificate::subjAltNames() const
1299 {
1300     QStringList rc;
1301 #if KSSL_HAVE_SSL
1302     STACK_OF(GENERAL_NAME) *names;
1303     names = (STACK_OF(GENERAL_NAME) *)d->kossl->X509_get_ext_d2i(d->m_cert, NID_subject_alt_name, nullptr, nullptr);
1304 
1305     if (!names) {
1306         return rc;
1307     }
1308 
1309     int cnt = d->kossl->OPENSSL_sk_num((STACK *)names);
1310 
1311     for (int i = 0; i < cnt; i++) {
1312         const GENERAL_NAME *val = (const GENERAL_NAME *)d->kossl->OPENSSL_sk_value(names, i);
1313         if (val->type != GEN_DNS) {
1314             continue;
1315         }
1316 
1317         QString s = (const char *)d->kossl->ASN1_STRING_data(val->d.ia5);
1318         if (!s.isEmpty()  &&
1319                 /* skip subjectAltNames with embedded NULs */
1320                 s.length() == d->kossl->ASN1_STRING_length(val->d.ia5)) {
1321             rc += s;
1322         }
1323     }
1324     d->kossl->OPENSSL_sk_free(names);
1325 #endif
1326     return rc;
1327 }
1328 
1329 QDataStream &operator<<(QDataStream &s, const KSSLCertificate &r)
1330 {
1331     QStringList qsl;
1332     QList<KSSLCertificate *> cl = const_cast<KSSLCertificate &>(r).chain().getChain();
1333 
1334     foreach (KSSLCertificate *c, cl) {
1335         qsl << c->toString();
1336     }
1337 
1338     qDeleteAll(cl);
1339     s << const_cast<KSSLCertificate &>(r).toString() << qsl;
1340 
1341     return s;
1342 }
1343 
1344 QDataStream &operator>>(QDataStream &s, KSSLCertificate &r)
1345 {
1346     QStringList qsl;
1347     QString cert;
1348 
1349     s >> cert >> qsl;
1350 
1351     if (r.setCert(cert) && !qsl.isEmpty()) {
1352         r.chain().setCertChain(qsl);
1353     }
1354 
1355     return s;
1356 }
1357