kio Library: ksmimecrypto.cc Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# ksmimecrypto.cc

    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., 59 Temple Place - Suite 330,
    00018  * Boston, MA 02111-1307, 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 }

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:04 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003