TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ksmimecrypto.cc 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. /* This file is part of the KDE project
  2. *
  3. * Copyright (C) 2003 Stefan Rompf <sux@loplof.de>
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Library General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Library General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Library General Public License
  16. * along with this library; see the file COPYING.LIB. If not, write to
  17. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  18. * Boston, MA 02110-1301, USA.
  19. */
  20. #include <tqptrlist.h>
  21. #include <tqcstring.h>
  22. #include <tqstring.h>
  23. #include <kdebug.h>
  24. #include "kopenssl.h"
  25. #include "ksslcertificate.h"
  26. #include "ksslpkcs12.h"
  27. #include "ksmimecrypto.h"
  28. // this hack provided by Malte Starostik to avoid glibc/openssl bug
  29. // on some systems
  30. #ifdef KSSL_HAVE_SSL
  31. #define crypt _openssl_crypt
  32. #include <openssl/err.h>
  33. #undef crypt
  34. #endif
  35. #ifdef KSSL_HAVE_SSL
  36. static const char eot = 0;
  37. class KSMIMECryptoPrivate {
  38. KOpenSSLProxy *kossl;
  39. public:
  40. KSMIMECryptoPrivate(KOpenSSLProxy *kossl);
  41. STACK_OF(X509) *certsToX509(TQPtrList<KSSLCertificate> &certs);
  42. KSMIMECrypto::rc signMessage(BIO *clearText,
  43. BIO *cipherText,
  44. KSSLPKCS12 &privKey, TQPtrList<KSSLCertificate> &certs,
  45. bool detached);
  46. KSMIMECrypto::rc encryptMessage(BIO *clearText,
  47. BIO *cipherText, KSMIMECrypto::algo algorithm,
  48. TQPtrList<KSSLCertificate> &recip);
  49. KSMIMECrypto::rc checkSignature(BIO *clearText,
  50. BIO *signature, bool detached,
  51. TQPtrList<KSSLCertificate> &recip);
  52. KSMIMECrypto::rc decryptMessage(BIO *cipherText,
  53. BIO *clearText,
  54. KSSLPKCS12 &privKey);
  55. void MemBIOToQByteArray(BIO *src, TQByteArray &dest);
  56. KSMIMECrypto::rc sslErrToRc(void);
  57. };
  58. KSMIMECryptoPrivate::KSMIMECryptoPrivate(KOpenSSLProxy *kossl): kossl(kossl) {
  59. }
  60. STACK_OF(X509) *KSMIMECryptoPrivate::certsToX509(TQPtrList<KSSLCertificate> &certs) {
  61. STACK_OF(X509) *x509 = reinterpret_cast<STACK_OF(X509)*>(kossl->OPENSSL_sk_new(NULL));
  62. KSSLCertificate *cert = certs.first();
  63. while(cert) {
  64. kossl->OPENSSL_sk_push(x509, cert->getCert());
  65. cert = certs.next();
  66. }
  67. return x509;
  68. }
  69. KSMIMECrypto::rc KSMIMECryptoPrivate::signMessage(BIO *clearText,
  70. BIO *cipherText,
  71. KSSLPKCS12 &privKey, TQPtrList<KSSLCertificate> &certs,
  72. bool detached) {
  73. STACK_OF(X509) *other = NULL;
  74. KSMIMECrypto::rc rc;
  75. int flags = detached?PKCS7_DETACHED:0;
  76. if (certs.count()) other = certsToX509(certs);
  77. PKCS7 *p7 = kossl->PKCS7_sign(privKey.getCertificate()->getCert(), privKey.getPrivateKey(),
  78. other, clearText, flags);
  79. if (other) kossl->OPENSSL_sk_free(other);
  80. if (!p7) return sslErrToRc();
  81. if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
  82. rc = KSMIMECrypto::KSC_R_OK;
  83. } else {
  84. rc = sslErrToRc();
  85. }
  86. kossl->PKCS7_free(p7);
  87. return rc;
  88. }
  89. KSMIMECrypto::rc KSMIMECryptoPrivate::encryptMessage(BIO *clearText,
  90. BIO *cipherText, KSMIMECrypto::algo algorithm,
  91. TQPtrList<KSSLCertificate> &recip) {
  92. EVP_CIPHER *cipher = NULL;
  93. KSMIMECrypto::rc rc;
  94. switch(algorithm) {
  95. case KSMIMECrypto::KSC_C_DES3_CBC:
  96. cipher = kossl->EVP_des_ede3_cbc();
  97. break;
  98. case KSMIMECrypto::KSC_C_RC2_CBC_128:
  99. cipher = kossl->EVP_rc2_cbc();
  100. break;
  101. case KSMIMECrypto::KSC_C_RC2_CBC_64:
  102. cipher = kossl->EVP_rc2_64_cbc();
  103. break;
  104. case KSMIMECrypto::KSC_C_DES_CBC:
  105. cipher = kossl->EVP_des_cbc();
  106. break;
  107. case KSMIMECrypto::KSC_C_RC2_CBC_40:
  108. cipher = kossl->EVP_rc2_40_cbc();
  109. break;
  110. }
  111. if (!cipher) return KSMIMECrypto::KSC_R_NOCIPHER;
  112. STACK_OF(X509) *certs = certsToX509(recip);
  113. PKCS7 *p7 = kossl->PKCS7_encrypt(certs, clearText, cipher, 0);
  114. kossl->OPENSSL_sk_free(certs);
  115. if (!p7) return sslErrToRc();
  116. if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
  117. rc = KSMIMECrypto::KSC_R_OK;
  118. } else {
  119. rc = sslErrToRc();
  120. }
  121. kossl->PKCS7_free(p7);
  122. return rc;
  123. }
  124. KSMIMECrypto::rc KSMIMECryptoPrivate::checkSignature(BIO *clearText,
  125. BIO *signature, bool detached,
  126. TQPtrList<KSSLCertificate> &recip) {
  127. PKCS7 *p7 = kossl->d2i_PKCS7_bio(signature, NULL);
  128. KSMIMECrypto::rc rc = KSMIMECrypto::KSC_R_OTHER;
  129. if (!p7) return sslErrToRc();
  130. BIO *in;
  131. BIO *out;
  132. if (detached) {
  133. in = clearText;
  134. out = NULL;
  135. } else {
  136. in = NULL;
  137. out = clearText;
  138. }
  139. X509_STORE *dummystore = kossl->X509_STORE_new();
  140. if (kossl->PKCS7_verify(p7, NULL, dummystore, in, out, PKCS7_NOVERIFY)) {
  141. STACK_OF(X509) *signers = kossl->PKCS7_get0_signers(p7, 0, PKCS7_NOVERIFY);
  142. int num = kossl->OPENSSL_sk_num(signers);
  143. for(int n=0; n<num; n++) {
  144. KSSLCertificate *signer = KSSLCertificate::fromX509(reinterpret_cast<X509*>(kossl->OPENSSL_sk_value(signers, n)));
  145. recip.append(signer);
  146. }
  147. kossl->OPENSSL_sk_free(signers);
  148. rc = KSMIMECrypto::KSC_R_OK;
  149. } else {
  150. rc = sslErrToRc();
  151. }
  152. kossl->X509_STORE_free(dummystore);
  153. kossl->PKCS7_free(p7);
  154. return rc;
  155. }
  156. KSMIMECrypto::rc KSMIMECryptoPrivate::decryptMessage(BIO *cipherText,
  157. BIO *clearText,
  158. KSSLPKCS12 &privKey) {
  159. PKCS7 *p7 = kossl->d2i_PKCS7_bio(cipherText, NULL);
  160. KSMIMECrypto::rc rc;
  161. if (!p7) return sslErrToRc();
  162. if (kossl->PKCS7_decrypt(p7, privKey.getPrivateKey(), privKey.getCertificate()->getCert(),
  163. clearText, 0)) {
  164. rc = KSMIMECrypto::KSC_R_OK;
  165. } else {
  166. rc = sslErrToRc();
  167. }
  168. kossl->PKCS7_free(p7);
  169. return rc;
  170. }
  171. void KSMIMECryptoPrivate::MemBIOToQByteArray(BIO *src, TQByteArray &dest) {
  172. char *buf;
  173. long len = kossl->BIO_get_mem_data(src, &buf);
  174. dest.assign(buf, len);
  175. /* Now this goes quite a bit into openssl internals.
  176. We assume that openssl uses malloc() (it does in
  177. default config) and rip out the buffer.
  178. */
  179. void *ptr = kossl->BIO_get_data(src);
  180. reinterpret_cast<BUF_MEM *>(ptr)->data = NULL;
  181. }
  182. KSMIMECrypto::rc KSMIMECryptoPrivate::sslErrToRc(void) {
  183. unsigned long cerr = kossl->ERR_get_error();
  184. // To be completed and possibly fixed
  185. switch(ERR_GET_REASON(cerr)) {
  186. case ERR_R_MALLOC_FAILURE:
  187. return KSMIMECrypto::KSC_R_NOMEM;
  188. }
  189. switch(ERR_GET_LIB(cerr)) {
  190. case ERR_LIB_PKCS7:
  191. switch(ERR_GET_REASON(cerr)) {
  192. case PKCS7_R_WRONG_CONTENT_TYPE:
  193. case PKCS7_R_NO_CONTENT:
  194. case PKCS7_R_NO_SIGNATURES_ON_DATA:
  195. return KSMIMECrypto::KSC_R_FORMAT;
  196. break;
  197. case PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE:
  198. case PKCS7_R_DECRYPT_ERROR: // Hmm?
  199. return KSMIMECrypto::KSC_R_WRONGKEY;
  200. break;
  201. case PKCS7_R_DIGEST_FAILURE:
  202. return KSMIMECrypto::KSC_R_VERIFY;
  203. default:
  204. break;
  205. }
  206. break;
  207. default:
  208. break;
  209. }
  210. kdDebug(7029) <<"KSMIMECrypto: uncaught error " <<ERR_GET_LIB(cerr)
  211. <<" " <<ERR_GET_REASON(cerr) <<endl;
  212. return KSMIMECrypto::KSC_R_OTHER;
  213. }
  214. #endif
  215. KSMIMECrypto::KSMIMECrypto() {
  216. #ifdef KSSL_HAVE_SSL
  217. kossl = KOpenSSLProxy::self();
  218. priv = new KSMIMECryptoPrivate(kossl);
  219. if (!kossl->hasLibCrypto()) kossl = 0L;
  220. #else
  221. kossl = 0L;
  222. #endif
  223. }
  224. KSMIMECrypto::~KSMIMECrypto() {
  225. #ifdef KSSL_HAVE_SSL
  226. delete priv;
  227. #endif
  228. }
  229. KSMIMECrypto::rc KSMIMECrypto::signMessage(const TQCString &clearText,
  230. TQByteArray &cipherText,
  231. const KSSLPKCS12 &privKey,
  232. const TQPtrList<KSSLCertificate> &certs,
  233. bool detached) {
  234. #ifdef KSSL_HAVE_SSL
  235. if (!kossl) return KSC_R_NO_SSL;
  236. BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
  237. BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
  238. rc rc = priv->signMessage(in, out,
  239. const_cast<KSSLPKCS12 &>(privKey),
  240. const_cast<TQPtrList<KSSLCertificate> &>(certs),
  241. detached);
  242. if (!rc) priv->MemBIOToQByteArray(out, cipherText);
  243. kossl->BIO_free(out);
  244. kossl->BIO_free(in);
  245. return rc;
  246. #else
  247. return KSC_R_NO_SSL;
  248. #endif
  249. }
  250. KSMIMECrypto::rc KSMIMECrypto::checkDetachedSignature(const TQCString &clearText,
  251. const TQByteArray &signature,
  252. TQPtrList<KSSLCertificate> &foundCerts) {
  253. #ifdef KSSL_HAVE_SSL
  254. if (!kossl) return KSC_R_NO_SSL;
  255. BIO *txt = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.length());
  256. BIO *sig = kossl->BIO_new_mem_buf((char *)signature.data(), signature.size());
  257. rc rc = priv->checkSignature(txt, sig, true, foundCerts);
  258. kossl->BIO_free(sig);
  259. kossl->BIO_free(txt);
  260. return rc;
  261. #else
  262. return KSC_R_NO_SSL;
  263. #endif
  264. }
  265. KSMIMECrypto::rc KSMIMECrypto::checkOpaqueSignature(const TQByteArray &signedText,
  266. TQCString &clearText,
  267. TQPtrList<KSSLCertificate> &foundCerts) {
  268. #ifdef KSSL_HAVE_SSL
  269. if (!kossl) return KSC_R_NO_SSL;
  270. BIO *in = kossl->BIO_new_mem_buf((char *)signedText.data(), signedText.size());
  271. BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
  272. rc rc = priv->checkSignature(out, in, false, foundCerts);
  273. kossl->BIO_write(out, &eot, 1);
  274. priv->MemBIOToQByteArray(out, clearText);
  275. kossl->BIO_free(out);
  276. kossl->BIO_free(in);
  277. return rc;
  278. #else
  279. return KSC_R_NO_SSL;
  280. #endif
  281. }
  282. KSMIMECrypto::rc KSMIMECrypto::encryptMessage(const TQCString &clearText,
  283. TQByteArray &cipherText,
  284. algo algorithm,
  285. const TQPtrList<KSSLCertificate> &recip) {
  286. #ifdef KSSL_HAVE_SSL
  287. if (!kossl) return KSC_R_NO_SSL;
  288. BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
  289. BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
  290. rc rc = priv->encryptMessage(in,out,algorithm,
  291. const_cast< TQPtrList<KSSLCertificate> &>(recip));
  292. if (!rc) priv->MemBIOToQByteArray(out, cipherText);
  293. kossl->BIO_free(out);
  294. kossl->BIO_free(in);
  295. return rc;
  296. #else
  297. return KSC_R_NO_SSL;
  298. #endif
  299. }
  300. KSMIMECrypto::rc KSMIMECrypto::decryptMessage(const TQByteArray &cipherText,
  301. TQCString &clearText,
  302. const KSSLPKCS12 &privKey) {
  303. #ifdef KSSL_HAVE_SSL
  304. if (!kossl) return KSC_R_NO_SSL;
  305. BIO *in = kossl->BIO_new_mem_buf((char *)cipherText.data(), cipherText.size());
  306. BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
  307. rc rc = priv->decryptMessage(in,out,
  308. const_cast<KSSLPKCS12 &>(privKey));
  309. kossl->BIO_write(out, &eot, 1);
  310. priv->MemBIOToQByteArray(out, clearText);
  311. kossl->BIO_free(out);
  312. kossl->BIO_free(in);
  313. return rc;
  314. #else
  315. return KSC_R_NO_SSL;
  316. #endif
  317. }