00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00033
00034 #ifdef KSSL_HAVE_SSL
00035 #define crypt _openssl_crypt
00036 #include <openssl/err.h>
00037 #undef crypt
00038 #endif
00039
00040
00041
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
00242
00243
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
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:
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 }