• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

ksmimecrypto.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) 2003 Stefan Rompf <sux@loplof.de>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 #include "ksmimecrypto.h"
00022 
00023 #include <QtCore/QList>
00024 #include <QtCore/QString>
00025 #include <kdebug.h>
00026 
00027 #include "kopenssl.h"
00028 #include "ksslcertificate.h"
00029 #include "ksslpkcs12.h"
00030 
00031 // this hack provided by Malte Starostik to avoid glibc/openssl bug
00032 // on some systems
00033 #ifdef KSSL_HAVE_SSL
00034 #define crypt _openssl_crypt
00035 #include <openssl/err.h>
00036 #undef crypt
00037 #endif
00038 
00039 
00040 // forward included macros to KOpenSSLProxy
00041 #define sk_new kossl->sk_new
00042 #define sk_free kossl->sk_free
00043 #define sk_push kossl->sk_push
00044 #define sk_value kossl->sk_value
00045 #define sk_num kossl->sk_num
00046 #define BIO_ctrl kossl->BIO_ctrl
00047 
00048 
00049 #ifdef KSSL_HAVE_SSL
00050 static const char eot = 0;
00051 
00052 class KSMIMECryptoPrivate {
00053     KOpenSSLProxy *kossl;
00054 
00055 public:
00056     KSMIMECryptoPrivate(KOpenSSLProxy *kossl);
00057 
00058 
00059     STACK_OF(X509) *certsToX509(const QList<KSSLCertificate *> &certs);
00060 
00061     KSMIMECrypto::rc signMessage(BIO *clearText,
00062                  BIO *cipherText,
00063                  KSSLPKCS12 &privKey, QList<KSSLCertificate *> &certs,
00064                  bool detached);
00065 
00066     KSMIMECrypto::rc encryptMessage(BIO *clearText,
00067                     BIO *cipherText, KSMIMECrypto::algo algorithm,
00068                     QList<KSSLCertificate *> &recip);
00069 
00070     KSMIMECrypto::rc checkSignature(BIO *clearText,
00071                     BIO *signature, bool detached,
00072                     QList<KSSLCertificate *> &recip);
00073 
00074     KSMIMECrypto::rc decryptMessage(BIO *cipherText,
00075                     BIO *clearText,
00076                     KSSLPKCS12 &privKey);
00077 
00078     void MemBIOToQByteArray(BIO *src, QByteArray &dest);
00079 
00080     KSMIMECrypto::rc sslErrToRc(void);
00081 };
00082 
00083 
00084 KSMIMECryptoPrivate::KSMIMECryptoPrivate(KOpenSSLProxy *kossl): kossl(kossl) {
00085 }
00086 
00087 
00088 STACK_OF(X509) *KSMIMECryptoPrivate::certsToX509(const QList<KSSLCertificate *> &certs) {
00089     STACK_OF(X509) *x509 = sk_new(NULL);
00090     foreach(KSSLCertificate *cert, certs) {
00091     sk_X509_push(x509, cert->getCert());
00092     }
00093     return x509;
00094 }
00095 
00096 
00097 KSMIMECrypto::rc KSMIMECryptoPrivate::signMessage(BIO *clearText,
00098                           BIO *cipherText,
00099                           KSSLPKCS12 &privKey, QList<KSSLCertificate *> &certs,
00100                           bool detached) {
00101 
00102     STACK_OF(X509) *other = NULL;
00103     KSMIMECrypto::rc rc;
00104     int flags = detached?PKCS7_DETACHED:0;
00105 
00106     if (certs.count()) other = certsToX509(certs);
00107 
00108     PKCS7 *p7 = kossl->PKCS7_sign(privKey.getCertificate()->getCert(), privKey.getPrivateKey(),
00109                   other, clearText, flags);
00110 
00111     if (other) sk_X509_free(other);
00112 
00113     if (!p7) return sslErrToRc();
00114 
00115     if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
00116     rc = KSMIMECrypto::KSC_R_OK;
00117     } else {
00118     rc = sslErrToRc();
00119     }
00120 
00121     kossl->PKCS7_free(p7);
00122 
00123     return rc;
00124 }
00125 
00126 KSMIMECrypto::rc KSMIMECryptoPrivate::encryptMessage(BIO *clearText,
00127                              BIO *cipherText, KSMIMECrypto::algo algorithm,
00128                              QList<KSSLCertificate *> &recip) {
00129     EVP_CIPHER *cipher = NULL;
00130     KSMIMECrypto::rc rc;
00131     switch(algorithm) {
00132     case KSMIMECrypto::KSC_C_DES3_CBC:
00133         cipher = kossl->EVP_des_ede3_cbc();
00134         break;
00135     case KSMIMECrypto::KSC_C_RC2_CBC_128:
00136         cipher = kossl->EVP_rc2_cbc();
00137         break;
00138     case KSMIMECrypto::KSC_C_RC2_CBC_64:
00139         cipher = kossl->EVP_rc2_64_cbc();
00140         break;
00141     case KSMIMECrypto::KSC_C_DES_CBC:
00142         cipher = kossl->EVP_des_cbc();
00143         break;
00144     case KSMIMECrypto::KSC_C_RC2_CBC_40:
00145         cipher = kossl->EVP_rc2_40_cbc();
00146         break;
00147     }
00148     if (!cipher) return KSMIMECrypto::KSC_R_NOCIPHER;
00149 
00150     STACK_OF(X509) *certs = certsToX509(recip);
00151 
00152     PKCS7 *p7 = kossl->PKCS7_encrypt(certs, clearText, cipher, 0);
00153 
00154     sk_X509_free(certs);
00155 
00156     if (!p7) return sslErrToRc();
00157 
00158     if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
00159     rc = KSMIMECrypto::KSC_R_OK;
00160     } else {
00161     rc = sslErrToRc();
00162     }
00163 
00164     kossl->PKCS7_free(p7);
00165 
00166     return rc;
00167 }
00168 
00169 
00170 KSMIMECrypto::rc KSMIMECryptoPrivate::checkSignature(BIO *clearText,
00171                              BIO *signature, bool detached,
00172                              QList<KSSLCertificate *> &recip) {
00173 
00174     PKCS7 *p7 = kossl->d2i_PKCS7_bio(signature, NULL);
00175     KSMIMECrypto::rc rc = KSMIMECrypto::KSC_R_OTHER;
00176 
00177     if (!p7) return sslErrToRc();
00178 
00179     BIO *in;
00180     BIO *out;
00181     if (detached) {
00182     in = clearText;
00183     out = NULL;
00184     } else {
00185     in = NULL;
00186     out = clearText;
00187     }
00188 
00189     X509_STORE *dummystore = kossl->X509_STORE_new();
00190     if (kossl->PKCS7_verify(p7, NULL, dummystore, in, out, PKCS7_NOVERIFY)) {
00191     STACK_OF(X509) *signers = kossl->PKCS7_get0_signers(p7, 0, PKCS7_NOVERIFY);
00192     int num = sk_X509_num(signers);
00193 
00194     for(int n=0; n<num; n++) {
00195         KSSLCertificate *signer = KSSLCertificate::fromX509(sk_X509_value(signers, n));
00196         recip.append(signer);
00197     }
00198 
00199     sk_X509_free(signers);
00200     rc = KSMIMECrypto::KSC_R_OK;
00201     } else {
00202     rc = sslErrToRc();
00203     }
00204 
00205     kossl->X509_STORE_free(dummystore);
00206     kossl->PKCS7_free(p7);
00207 
00208     return rc;
00209 }
00210 
00211 
00212 KSMIMECrypto::rc KSMIMECryptoPrivate::decryptMessage(BIO *cipherText,
00213                              BIO *clearText,
00214                              KSSLPKCS12 &privKey) {
00215 
00216     PKCS7 *p7 = kossl->d2i_PKCS7_bio(cipherText, NULL);
00217     KSMIMECrypto::rc rc;
00218 
00219     if (!p7) return sslErrToRc();
00220 
00221     if (kossl->PKCS7_decrypt(p7, privKey.getPrivateKey(), privKey.getCertificate()->getCert(),
00222                  clearText, 0)) {
00223     rc = KSMIMECrypto::KSC_R_OK;
00224     } else {
00225     rc = sslErrToRc();
00226     }
00227 
00228     kossl->PKCS7_free(p7);
00229 
00230     return rc;
00231 }
00232 
00233 
00234 void KSMIMECryptoPrivate::MemBIOToQByteArray(BIO *src, QByteArray &dest) {
00235     char *buf;
00236     long len = BIO_get_mem_data(src, &buf);
00237     dest = QByteArray(buf, len);
00238     /* Now this goes quite a bit into openssl internals.
00239        We assume that openssl uses malloc() (it does in
00240        default config) and rip out the buffer.
00241     */
00242     reinterpret_cast<BUF_MEM *>(src->ptr)->data = NULL;
00243 }
00244 
00245 
00246 KSMIMECrypto::rc KSMIMECryptoPrivate::sslErrToRc(void) {
00247     unsigned long cerr = kossl->ERR_get_error();
00248 
00249     // To be completed and possibly fixed
00250 
00251     switch(ERR_GET_REASON(cerr)) {
00252     case ERR_R_MALLOC_FAILURE:
00253         return KSMIMECrypto::KSC_R_NOMEM;
00254     }
00255 
00256     switch(ERR_GET_LIB(cerr)) {
00257     case ERR_LIB_PKCS7:
00258         switch(ERR_GET_REASON(cerr)) {
00259         case PKCS7_R_WRONG_CONTENT_TYPE:
00260         case PKCS7_R_NO_CONTENT:
00261         case PKCS7_R_NO_SIGNATURES_ON_DATA:
00262             return KSMIMECrypto::KSC_R_FORMAT;
00263             break;
00264         case PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE:
00265         case PKCS7_R_DECRYPT_ERROR: // Hmm?
00266             return KSMIMECrypto::KSC_R_WRONGKEY;
00267             break;
00268         case PKCS7_R_DIGEST_FAILURE:
00269             return KSMIMECrypto::KSC_R_VERIFY;
00270         default:
00271             break;
00272         }
00273         break;
00274     default:
00275         break;
00276     }
00277 
00278     kDebug(7029) <<"KSMIMECrypto: uncaught error " <<ERR_GET_LIB(cerr)
00279           <<" " <<ERR_GET_REASON(cerr) <<endl;
00280     return KSMIMECrypto::KSC_R_OTHER;
00281 }
00282 #endif
00283 
00284 
00285 KSMIMECrypto::KSMIMECrypto() {
00286 #ifdef KSSL_HAVE_SSL
00287     kossl = KOpenSSLProxy::self();
00288     priv = new KSMIMECryptoPrivate(kossl);
00289     if (!kossl->hasLibCrypto()) kossl = 0L;
00290 #else
00291     kossl = 0L;
00292     priv = 0L;
00293 #endif
00294 }
00295 
00296 
00297 KSMIMECrypto::~KSMIMECrypto() {
00298 #ifdef KSSL_HAVE_SSL
00299     delete priv;
00300 #endif
00301 }
00302 
00303 
00304 KSMIMECrypto::rc KSMIMECrypto::signMessage(const QByteArray &clearText,
00305                        QByteArray &cipherText,
00306                        const KSSLPKCS12 &privKey,
00307                        const QList<KSSLCertificate *> &certs,
00308                        bool detached) {
00309 #ifdef KSSL_HAVE_SSL
00310     if (!kossl) return KSC_R_NO_SSL;
00311     BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
00312     BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
00313 
00314     rc rc = priv->signMessage(in, out,
00315                   const_cast<KSSLPKCS12 &>(privKey),
00316                   const_cast<QList<KSSLCertificate *> &>(certs),
00317                   detached);
00318 
00319     if (!rc) priv->MemBIOToQByteArray(out, cipherText);
00320 
00321     kossl->BIO_free(out);
00322     kossl->BIO_free(in);
00323 
00324     return rc;
00325 #else
00326     return KSC_R_NO_SSL;
00327 #endif
00328 }
00329 
00330 
00331 KSMIMECrypto::rc KSMIMECrypto::checkDetachedSignature(const QByteArray &clearText,
00332                               const QByteArray &signature,
00333                               QList<KSSLCertificate *> &foundCerts) {
00334 #ifdef KSSL_HAVE_SSL
00335     if (!kossl) return KSC_R_NO_SSL;
00336     BIO *txt = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.length());
00337     BIO *sig = kossl->BIO_new_mem_buf((char *)signature.data(), signature.size());
00338 
00339     rc rc = priv->checkSignature(txt, sig, true, foundCerts);
00340 
00341     kossl->BIO_free(sig);
00342     kossl->BIO_free(txt);
00343 
00344     return rc;
00345 #else
00346     return KSC_R_NO_SSL;
00347 #endif
00348 }
00349 
00350 
00351 KSMIMECrypto::rc KSMIMECrypto::checkOpaqueSignature(const QByteArray &signedText,
00352                             QByteArray &clearText,
00353                             QList<KSSLCertificate *> &foundCerts) {
00354 #ifdef KSSL_HAVE_SSL
00355     if (!kossl) return KSC_R_NO_SSL;
00356 
00357     BIO *in = kossl->BIO_new_mem_buf((char *)signedText.data(), signedText.size());
00358     BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
00359 
00360     rc rc = priv->checkSignature(out, in, false, foundCerts);
00361 
00362     kossl->BIO_write(out, &eot, 1);
00363     priv->MemBIOToQByteArray(out, clearText);
00364 
00365     kossl->BIO_free(out);
00366     kossl->BIO_free(in);
00367 
00368     return rc;
00369 #else
00370     return KSC_R_NO_SSL;
00371 #endif
00372 }
00373 
00374 
00375 KSMIMECrypto::rc KSMIMECrypto::encryptMessage(const QByteArray &clearText,
00376                           QByteArray &cipherText,
00377                           algo algorithm,
00378                           const QList<KSSLCertificate *> &recip) {
00379 #ifdef KSSL_HAVE_SSL
00380     if (!kossl) return KSC_R_NO_SSL;
00381 
00382     BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
00383     BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
00384 
00385     rc rc = priv->encryptMessage(in,out,algorithm,
00386                  const_cast< QList<KSSLCertificate *> &>(recip));
00387 
00388     if (!rc) priv->MemBIOToQByteArray(out, cipherText);
00389 
00390     kossl->BIO_free(out);
00391     kossl->BIO_free(in);
00392 
00393     return rc;
00394 #else
00395     return KSC_R_NO_SSL;
00396 #endif
00397 }
00398 
00399 
00400 KSMIMECrypto::rc KSMIMECrypto::decryptMessage(const QByteArray &cipherText,
00401                           QByteArray &clearText,
00402                           const KSSLPKCS12 &privKey) {
00403 #ifdef KSSL_HAVE_SSL
00404     if (!kossl) return KSC_R_NO_SSL;
00405 
00406     BIO *in = kossl->BIO_new_mem_buf((char *)cipherText.data(), cipherText.size());
00407     BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
00408 
00409     rc rc = priv->decryptMessage(in,out,
00410                  const_cast<KSSLPKCS12 &>(privKey));
00411 
00412     kossl->BIO_write(out, &eot, 1);
00413     priv->MemBIOToQByteArray(out, clearText);
00414 
00415     kossl->BIO_free(out);
00416     kossl->BIO_free(in);
00417 
00418     return rc;
00419 #else
00420     return KSC_R_NO_SSL;
00421 #endif
00422 }

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal