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