File indexing completed on 2024-03-24 15:27:56

0001 /* This file is part of the KDE project
0002  *
0003  * Copyright (C) 2001 George Staikos <staikos@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 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  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #include "ksslcertchain.h"
0022 
0023 #include <ksslconfig.h>
0024 
0025 #include "ksslcertificate.h"
0026 
0027 // this hack provided by Malte Starostik to avoid glibc/openssl bug
0028 // on some systems
0029 #if KSSL_HAVE_SSL
0030 #define crypt _openssl_crypt
0031 #include <openssl/ssl.h>
0032 #include <openssl/x509.h>
0033 #include <openssl/x509v3.h>
0034 #include <openssl/x509_vfy.h>
0035 #include <openssl/pem.h>
0036 #include <openssl/stack.h>
0037 #include <openssl/safestack.h>
0038 #undef crypt
0039 #endif
0040 
0041 #include <kopenssl.h>
0042 #include <QStringList>
0043 
0044 class KSSLCertChainPrivate
0045 {
0046 public:
0047     KSSLCertChainPrivate()
0048     {
0049         kossl = KOSSL::self();
0050     }
0051 
0052     ~KSSLCertChainPrivate()
0053     {
0054     }
0055 
0056     KOSSL *kossl;
0057 };
0058 
0059 KSSLCertChain::KSSLCertChain()
0060     : d(new KSSLCertChainPrivate)
0061 {
0062     _chain = nullptr;
0063 }
0064 
0065 KSSLCertChain::~KSSLCertChain()
0066 {
0067 #if KSSL_HAVE_SSL
0068     if (_chain) {
0069         STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
0070 
0071         for (;;) {
0072             X509 *x5 = reinterpret_cast<X509*>(d->kossl->OPENSSL_sk_pop(reinterpret_cast<STACK *>(x)));
0073             if (!x5) {
0074                 break;
0075             }
0076             d->kossl->X509_free(x5);
0077         }
0078         d->kossl->OPENSSL_sk_free(reinterpret_cast<STACK *>(x));
0079     }
0080 #endif
0081     delete d;
0082 }
0083 
0084 bool KSSLCertChain::isValid()
0085 {
0086     return (_chain && depth() > 0);
0087 }
0088 
0089 KSSLCertChain *KSSLCertChain::replicate()
0090 {
0091     KSSLCertChain *x = new KSSLCertChain;
0092     QList<KSSLCertificate *> ch = getChain();
0093     x->setChain(ch);   // this will do a deep copy for us
0094     qDeleteAll(ch);
0095     return x;
0096 }
0097 
0098 int KSSLCertChain::depth()
0099 {
0100 #if KSSL_HAVE_SSL
0101     return d->kossl->OPENSSL_sk_num(static_cast<STACK *>(_chain));
0102 #endif
0103     return 0;
0104 }
0105 
0106 void *KSSLCertChain::rawChain()
0107 {
0108     return _chain;
0109 }
0110 
0111 QList<KSSLCertificate *> KSSLCertChain::getChain() const
0112 {
0113     QList<KSSLCertificate *> cl;
0114     if (!_chain) {
0115         return cl;
0116     }
0117 #if KSSL_HAVE_SSL
0118     STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
0119 
0120     for (int i = 0; i < d->kossl->OPENSSL_sk_num(reinterpret_cast<STACK *>(x)); i++) {
0121         X509 *x5 =  reinterpret_cast<X509*>(d->kossl->OPENSSL_sk_value(reinterpret_cast<STACK *>(x), i));
0122         if (!x5) {
0123             continue;
0124         }
0125         KSSLCertificate *nc = new KSSLCertificate;
0126         nc->setCert(d->kossl->X509_dup(x5));
0127         cl.append(nc);
0128     }
0129 
0130 #endif
0131     return cl;
0132 }
0133 
0134 void KSSLCertChain::setChain(const QList<KSSLCertificate *> &chain)
0135 {
0136 #if KSSL_HAVE_SSL
0137     if (_chain) {
0138         STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
0139 
0140         for (;;) {
0141             X509 *x5 = reinterpret_cast<X509*>(d->kossl->OPENSSL_sk_pop(reinterpret_cast<STACK*>(x)));
0142             if (!x5) {
0143                 break;
0144             }
0145             d->kossl->X509_free(x5);
0146         }
0147         d->kossl->OPENSSL_sk_free(reinterpret_cast<STACK*>(x));
0148         _chain = nullptr;
0149     }
0150 
0151     if (chain.isEmpty()) {
0152         return;
0153     }
0154     _chain = (void *)d->kossl->OPENSSL_sk_new(nullptr);
0155     foreach (KSSLCertificate *x, chain) {
0156         d->kossl->OPENSSL_sk_push(static_cast<STACK*>(_chain), d->kossl->X509_dup(x->getCert()));
0157     }
0158 
0159 #endif
0160 }
0161 
0162 void KSSLCertChain::setChain(void *stack_of_x509)
0163 {
0164 #if KSSL_HAVE_SSL
0165     if (_chain) {
0166         STACK_OF(X509) *x = (STACK_OF(X509) *)_chain;
0167 
0168         for (;;) {
0169             X509 *x5 = reinterpret_cast<X509 *>(d->kossl->OPENSSL_sk_pop(reinterpret_cast<STACK *>(x)));
0170             if (!x5) {
0171                 break;
0172             }
0173             d->kossl->X509_free(x5);
0174         }
0175         d->kossl->OPENSSL_sk_free(reinterpret_cast<STACK *>(x));
0176         _chain = nullptr;
0177     }
0178 
0179     if (!stack_of_x509) {
0180         return;
0181     }
0182 
0183     _chain = (void *)d->kossl->OPENSSL_sk_new(nullptr);
0184     STACK_OF(X509) *x = (STACK_OF(X509) *)stack_of_x509;
0185 
0186     for (int i = 0; i < d->kossl->OPENSSL_sk_num(reinterpret_cast<STACK *>(x)); i++) {
0187         X509 *x5 = reinterpret_cast<X509*>(d->kossl->OPENSSL_sk_value(reinterpret_cast<STACK *>(x), i));
0188         if (!x5) {
0189             continue;
0190         }
0191         d->kossl->OPENSSL_sk_push(reinterpret_cast<STACK *>(_chain), d->kossl->X509_dup(x5));
0192     }
0193 
0194 #else
0195     _chain = NULL;
0196 #endif
0197 }
0198 
0199 void KSSLCertChain::setCertChain(const QStringList &chain)
0200 {
0201     QList<KSSLCertificate *> cl;
0202     for (QStringList::ConstIterator s = chain.begin(); s != chain.end(); ++s) {
0203         KSSLCertificate *c = KSSLCertificate::fromString((*s).toLocal8Bit());
0204         if (c) {
0205             cl.append(c);
0206         }
0207     }
0208     setChain(cl);
0209 }