kio Library API Documentation

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 #include "ksslconfig.h" 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 }
KDE Logo
This file is part of the documentation for kio Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 16 17:22:31 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003