• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.2 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • kssl
ksmimecrypto.cpp
Go to the documentation of this file.
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 
21 #include "ksmimecrypto.h"
22 
23 #include <QtCore/QList>
24 #include <QtCore/QString>
25 #include <kdebug.h>
26 
27 #include "kopenssl.h"
28 #include "ksslcertificate.h"
29 #include "ksslpkcs12.h"
30 
31 // this hack provided by Malte Starostik to avoid glibc/openssl bug
32 // on some systems
33 #ifdef KSSL_HAVE_SSL
34 #define crypt _openssl_crypt
35 #include <openssl/err.h>
36 #undef crypt
37 #endif
38 
39 
40 // forward included macros to KOpenSSLProxy
41 #define sk_new kossl->sk_new
42 #define sk_free kossl->sk_free
43 #define sk_push kossl->sk_push
44 #define sk_value kossl->sk_value
45 #define sk_num kossl->sk_num
46 #define BIO_ctrl kossl->BIO_ctrl
47 
48 
49 #ifdef KSSL_HAVE_SSL
50 static const char eot = 0;
51 
52 class KSMIMECryptoPrivate {
53  KOpenSSLProxy *kossl;
54 
55 public:
56  KSMIMECryptoPrivate(KOpenSSLProxy *kossl);
57 
58 
59  STACK_OF(X509) *certsToX509(const QList<KSSLCertificate *> &certs);
60 
61  KSMIMECrypto::rc signMessage(BIO *clearText,
62  BIO *cipherText,
63  KSSLPKCS12 &privKey, QList<KSSLCertificate *> &certs,
64  bool detached);
65 
66  KSMIMECrypto::rc encryptMessage(BIO *clearText,
67  BIO *cipherText, KSMIMECrypto::algo algorithm,
68  QList<KSSLCertificate *> &recip);
69 
70  KSMIMECrypto::rc checkSignature(BIO *clearText,
71  BIO *signature, bool detached,
72  QList<KSSLCertificate *> &recip);
73 
74  KSMIMECrypto::rc decryptMessage(BIO *cipherText,
75  BIO *clearText,
76  KSSLPKCS12 &privKey);
77 
78  void MemBIOToQByteArray(BIO *src, QByteArray &dest);
79 
80  KSMIMECrypto::rc sslErrToRc(void);
81 };
82 
83 
84 KSMIMECryptoPrivate::KSMIMECryptoPrivate(KOpenSSLProxy *kossl): kossl(kossl) {
85 }
86 
87 
88 STACK_OF(X509) *KSMIMECryptoPrivate::certsToX509(const QList<KSSLCertificate *> &certs) {
89  STACK_OF(X509) *x509 = sk_new(NULL);
90  foreach(KSSLCertificate *cert, certs) {
91  sk_X509_push(x509, cert->getCert());
92  }
93  return x509;
94 }
95 
96 
97 KSMIMECrypto::rc KSMIMECryptoPrivate::signMessage(BIO *clearText,
98  BIO *cipherText,
99  KSSLPKCS12 &privKey, QList<KSSLCertificate *> &certs,
100  bool detached) {
101 
102  STACK_OF(X509) *other = NULL;
103  KSMIMECrypto::rc rc;
104  int flags = detached?PKCS7_DETACHED:0;
105 
106  if (certs.count()) other = certsToX509(certs);
107 
108  PKCS7 *p7 = kossl->PKCS7_sign(privKey.getCertificate()->getCert(), privKey.getPrivateKey(),
109  other, clearText, flags);
110 
111  if (other) sk_X509_free(other);
112 
113  if (!p7) return sslErrToRc();
114 
115  if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
116  rc = KSMIMECrypto::KSC_R_OK;
117  } else {
118  rc = sslErrToRc();
119  }
120 
121  kossl->PKCS7_free(p7);
122 
123  return rc;
124 }
125 
126 KSMIMECrypto::rc KSMIMECryptoPrivate::encryptMessage(BIO *clearText,
127  BIO *cipherText, KSMIMECrypto::algo algorithm,
128  QList<KSSLCertificate *> &recip) {
129  EVP_CIPHER *cipher = NULL;
130  KSMIMECrypto::rc rc;
131  switch(algorithm) {
132  case KSMIMECrypto::KSC_C_DES3_CBC:
133  cipher = kossl->EVP_des_ede3_cbc();
134  break;
135  case KSMIMECrypto::KSC_C_RC2_CBC_128:
136  cipher = kossl->EVP_rc2_cbc();
137  break;
138  case KSMIMECrypto::KSC_C_RC2_CBC_64:
139  cipher = kossl->EVP_rc2_64_cbc();
140  break;
141  case KSMIMECrypto::KSC_C_DES_CBC:
142  cipher = kossl->EVP_des_cbc();
143  break;
144  case KSMIMECrypto::KSC_C_RC2_CBC_40:
145  cipher = kossl->EVP_rc2_40_cbc();
146  break;
147  }
148  if (!cipher) return KSMIMECrypto::KSC_R_NOCIPHER;
149 
150  STACK_OF(X509) *certs = certsToX509(recip);
151 
152  PKCS7 *p7 = kossl->PKCS7_encrypt(certs, clearText, cipher, 0);
153 
154  sk_X509_free(certs);
155 
156  if (!p7) return sslErrToRc();
157 
158  if (kossl->i2d_PKCS7_bio(cipherText, p7)) {
159  rc = KSMIMECrypto::KSC_R_OK;
160  } else {
161  rc = sslErrToRc();
162  }
163 
164  kossl->PKCS7_free(p7);
165 
166  return rc;
167 }
168 
169 
170 KSMIMECrypto::rc KSMIMECryptoPrivate::checkSignature(BIO *clearText,
171  BIO *signature, bool detached,
172  QList<KSSLCertificate *> &recip) {
173 
174  PKCS7 *p7 = kossl->d2i_PKCS7_bio(signature, NULL);
175  KSMIMECrypto::rc rc = KSMIMECrypto::KSC_R_OTHER;
176 
177  if (!p7) return sslErrToRc();
178 
179  BIO *in;
180  BIO *out;
181  if (detached) {
182  in = clearText;
183  out = NULL;
184  } else {
185  in = NULL;
186  out = clearText;
187  }
188 
189  X509_STORE *dummystore = kossl->X509_STORE_new();
190  if (kossl->PKCS7_verify(p7, NULL, dummystore, in, out, PKCS7_NOVERIFY)) {
191  STACK_OF(X509) *signers = kossl->PKCS7_get0_signers(p7, 0, PKCS7_NOVERIFY);
192  int num = sk_X509_num(signers);
193 
194  for(int n=0; n<num; n++) {
195  KSSLCertificate *signer = KSSLCertificate::fromX509(sk_X509_value(signers, n));
196  recip.append(signer);
197  }
198 
199  sk_X509_free(signers);
200  rc = KSMIMECrypto::KSC_R_OK;
201  } else {
202  rc = sslErrToRc();
203  }
204 
205  kossl->X509_STORE_free(dummystore);
206  kossl->PKCS7_free(p7);
207 
208  return rc;
209 }
210 
211 
212 KSMIMECrypto::rc KSMIMECryptoPrivate::decryptMessage(BIO *cipherText,
213  BIO *clearText,
214  KSSLPKCS12 &privKey) {
215 
216  PKCS7 *p7 = kossl->d2i_PKCS7_bio(cipherText, NULL);
217  KSMIMECrypto::rc rc;
218 
219  if (!p7) return sslErrToRc();
220 
221  if (kossl->PKCS7_decrypt(p7, privKey.getPrivateKey(), privKey.getCertificate()->getCert(),
222  clearText, 0)) {
223  rc = KSMIMECrypto::KSC_R_OK;
224  } else {
225  rc = sslErrToRc();
226  }
227 
228  kossl->PKCS7_free(p7);
229 
230  return rc;
231 }
232 
233 
234 void KSMIMECryptoPrivate::MemBIOToQByteArray(BIO *src, QByteArray &dest) {
235  char *buf;
236  long len = BIO_get_mem_data(src, &buf);
237  dest = QByteArray(buf, len);
238  /* Now this goes quite a bit into openssl internals.
239  We assume that openssl uses malloc() (it does in
240  default config) and rip out the buffer.
241  */
242  reinterpret_cast<BUF_MEM *>(src->ptr)->data = NULL;
243 }
244 
245 
246 KSMIMECrypto::rc KSMIMECryptoPrivate::sslErrToRc(void) {
247  unsigned long cerr = kossl->ERR_get_error();
248 
249  // To be completed and possibly fixed
250 
251  switch(ERR_GET_REASON(cerr)) {
252  case ERR_R_MALLOC_FAILURE:
253  return KSMIMECrypto::KSC_R_NOMEM;
254  }
255 
256  switch(ERR_GET_LIB(cerr)) {
257  case ERR_LIB_PKCS7:
258  switch(ERR_GET_REASON(cerr)) {
259  case PKCS7_R_WRONG_CONTENT_TYPE:
260  case PKCS7_R_NO_CONTENT:
261  case PKCS7_R_NO_SIGNATURES_ON_DATA:
262  return KSMIMECrypto::KSC_R_FORMAT;
263  break;
264  case PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE:
265  case PKCS7_R_DECRYPT_ERROR: // Hmm?
266  return KSMIMECrypto::KSC_R_WRONGKEY;
267  break;
268  case PKCS7_R_DIGEST_FAILURE:
269  return KSMIMECrypto::KSC_R_VERIFY;
270  default:
271  break;
272  }
273  break;
274  default:
275  break;
276  }
277 
278  kDebug(7029) <<"KSMIMECrypto: uncaught error " <<ERR_GET_LIB(cerr)
279  <<" " <<ERR_GET_REASON(cerr) <<endl;
280  return KSMIMECrypto::KSC_R_OTHER;
281 }
282 #endif
283 
284 
285 KSMIMECrypto::KSMIMECrypto() {
286 #ifdef KSSL_HAVE_SSL
287  kossl = KOpenSSLProxy::self();
288  priv = new KSMIMECryptoPrivate(kossl);
289  if (!kossl->hasLibCrypto()) kossl = 0L;
290 #else
291  kossl = 0L;
292  priv = 0L;
293 #endif
294 }
295 
296 
297 KSMIMECrypto::~KSMIMECrypto() {
298 #ifdef KSSL_HAVE_SSL
299  delete priv;
300 #endif
301 }
302 
303 
304 KSMIMECrypto::rc KSMIMECrypto::signMessage(const QByteArray &clearText,
305  QByteArray &cipherText,
306  const KSSLPKCS12 &privKey,
307  const QList<KSSLCertificate *> &certs,
308  bool detached) {
309 #ifdef KSSL_HAVE_SSL
310  if (!kossl) return KSC_R_NO_SSL;
311  BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
312  BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
313 
314  rc rc = priv->signMessage(in, out,
315  const_cast<KSSLPKCS12 &>(privKey),
316  const_cast<QList<KSSLCertificate *> &>(certs),
317  detached);
318 
319  if (!rc) priv->MemBIOToQByteArray(out, cipherText);
320 
321  kossl->BIO_free(out);
322  kossl->BIO_free(in);
323 
324  return rc;
325 #else
326  return KSC_R_NO_SSL;
327 #endif
328 }
329 
330 
331 KSMIMECrypto::rc KSMIMECrypto::checkDetachedSignature(const QByteArray &clearText,
332  const QByteArray &signature,
333  QList<KSSLCertificate *> &foundCerts) {
334 #ifdef KSSL_HAVE_SSL
335  if (!kossl) return KSC_R_NO_SSL;
336  BIO *txt = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.length());
337  BIO *sig = kossl->BIO_new_mem_buf((char *)signature.data(), signature.size());
338 
339  rc rc = priv->checkSignature(txt, sig, true, foundCerts);
340 
341  kossl->BIO_free(sig);
342  kossl->BIO_free(txt);
343 
344  return rc;
345 #else
346  return KSC_R_NO_SSL;
347 #endif
348 }
349 
350 
351 KSMIMECrypto::rc KSMIMECrypto::checkOpaqueSignature(const QByteArray &signedText,
352  QByteArray &clearText,
353  QList<KSSLCertificate *> &foundCerts) {
354 #ifdef KSSL_HAVE_SSL
355  if (!kossl) return KSC_R_NO_SSL;
356 
357  BIO *in = kossl->BIO_new_mem_buf((char *)signedText.data(), signedText.size());
358  BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
359 
360  rc rc = priv->checkSignature(out, in, false, foundCerts);
361 
362  kossl->BIO_write(out, &eot, 1);
363  priv->MemBIOToQByteArray(out, clearText);
364 
365  kossl->BIO_free(out);
366  kossl->BIO_free(in);
367 
368  return rc;
369 #else
370  return KSC_R_NO_SSL;
371 #endif
372 }
373 
374 
375 KSMIMECrypto::rc KSMIMECrypto::encryptMessage(const QByteArray &clearText,
376  QByteArray &cipherText,
377  algo algorithm,
378  const QList<KSSLCertificate *> &recip) {
379 #ifdef KSSL_HAVE_SSL
380  if (!kossl) return KSC_R_NO_SSL;
381 
382  BIO *in = kossl->BIO_new_mem_buf((char *)clearText.data(), clearText.size());
383  BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
384 
385  rc rc = priv->encryptMessage(in,out,algorithm,
386  const_cast< QList<KSSLCertificate *> &>(recip));
387 
388  if (!rc) priv->MemBIOToQByteArray(out, cipherText);
389 
390  kossl->BIO_free(out);
391  kossl->BIO_free(in);
392 
393  return rc;
394 #else
395  return KSC_R_NO_SSL;
396 #endif
397 }
398 
399 
400 KSMIMECrypto::rc KSMIMECrypto::decryptMessage(const QByteArray &cipherText,
401  QByteArray &clearText,
402  const KSSLPKCS12 &privKey) {
403 #ifdef KSSL_HAVE_SSL
404  if (!kossl) return KSC_R_NO_SSL;
405 
406  BIO *in = kossl->BIO_new_mem_buf((char *)cipherText.data(), cipherText.size());
407  BIO *out = kossl->BIO_new(kossl->BIO_s_mem());
408 
409  rc rc = priv->decryptMessage(in,out,
410  const_cast<KSSLPKCS12 &>(privKey));
411 
412  kossl->BIO_write(out, &eot, 1);
413  priv->MemBIOToQByteArray(out, clearText);
414 
415  kossl->BIO_free(out);
416  kossl->BIO_free(in);
417 
418  return rc;
419 #else
420  return KSC_R_NO_SSL;
421 #endif
422 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Apr 20 2013 06:03:11 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.10.2 API Reference

Skip menu "kdelibs-4.10.2 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal