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

kio

ksmimecrypto.cc

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

kio

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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