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