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.

security.cpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /***************************************************************************
  2. security.cpp - description
  3. -------------------
  4. begin : Thu Jun 24 11:22:12 2004
  5. copyright : (C) 2004, 2005 by Andras Mantia <amantia@kde.org>
  6. ***************************************************************************/
  7. /***************************************************************************
  8. * *
  9. * This program is free software; you can redistribute it and/or modify *
  10. * it under the terms of the GNU Library General Public License as *
  11. * published by the Free Software Foundation; version 2 of the License. *
  12. * *
  13. ***************************************************************************/
  14. //qt includes
  15. #include <tqfile.h>
  16. #include <tqfileinfo.h>
  17. #include <tqstringlist.h>
  18. #include <tqtimer.h>
  19. //kde includes
  20. #include <kdebug.h>
  21. #include <kinputdialog.h>
  22. #include <tdelocale.h>
  23. #include <kmdcodec.h>
  24. #include <tdemessagebox.h>
  25. #include <kpassdlg.h>
  26. #include <kprocio.h>
  27. //app includes
  28. #include "security.h"
  29. using namespace KNS;
  30. Security::Security()
  31. {
  32. m_keysRead = false;
  33. m_gpgRunning = false;
  34. readKeys();
  35. readSecretKeys();
  36. }
  37. Security::~Security()
  38. {
  39. }
  40. void Security::readKeys()
  41. {
  42. if (m_gpgRunning)
  43. {
  44. TQTimer::singleShot(5, this, TQT_SLOT(readKeys()));
  45. return;
  46. }
  47. m_runMode = List;
  48. m_keys.clear();
  49. KProcIO *readProcess=new KProcIO();
  50. *readProcess << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-keys";
  51. connect(readProcess, TQT_SIGNAL(processExited(TDEProcess *)), this, TQT_SLOT(slotProcessExited(TDEProcess *)));
  52. connect(readProcess, TQT_SIGNAL(readReady(KProcIO *)) ,this, TQT_SLOT(slotDataArrived(KProcIO *)));
  53. if (!readProcess->start(TDEProcess::NotifyOnExit, true))
  54. KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and retrieve the available keys. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>"));
  55. else
  56. m_gpgRunning = true;
  57. }
  58. void Security::readSecretKeys()
  59. {
  60. if (m_gpgRunning)
  61. {
  62. TQTimer::singleShot(5, this, TQT_SLOT(readSecretKeys()));
  63. return;
  64. }
  65. m_runMode = ListSecret;
  66. KProcIO *readProcess=new KProcIO();
  67. *readProcess << "gpg"<<"--no-secmem-warning"<<"--no-tty"<<"--with-colon"<<"--list-secret-keys";
  68. connect(readProcess, TQT_SIGNAL(processExited(TDEProcess *)), this, TQT_SLOT(slotProcessExited(TDEProcess *)));
  69. connect(readProcess, TQT_SIGNAL(readReady(KProcIO *)) ,this, TQT_SLOT(slotDataArrived(KProcIO *)));
  70. if (readProcess->start(TDEProcess::NotifyOnExit, true))
  71. m_gpgRunning = true;
  72. }
  73. void Security::slotProcessExited(TDEProcess *process)
  74. {
  75. switch (m_runMode)
  76. {
  77. case ListSecret:
  78. m_keysRead = true;
  79. break;
  80. case Verify: emit validityResult(m_result);
  81. break;
  82. case Sign: emit fileSigned(m_result);
  83. break;
  84. }
  85. m_gpgRunning = false;
  86. delete process;
  87. }
  88. void Security::slotDataArrived(KProcIO *procIO)
  89. {
  90. TQString data;
  91. while (procIO->readln(data, true) != -1)
  92. {
  93. switch (m_runMode)
  94. {
  95. case List:
  96. case ListSecret:
  97. if (data.startsWith("pub") || data.startsWith("sec"))
  98. {
  99. KeyStruct key;
  100. if (data.startsWith("pub"))
  101. key.secret = false;
  102. else
  103. key.secret = true;
  104. TQStringList line = TQStringList::split(":", data, true);
  105. key.id = line[4];
  106. TQString shortId = key.id.right(8);
  107. TQString trustStr = line[1];
  108. key.trusted = false;
  109. if (trustStr == "u" || trustStr == "f")
  110. key.trusted = true;
  111. data = line[9];
  112. key.mail=data.section('<', -1, -1);
  113. key.mail.truncate(key.mail.length() - 1);
  114. key.name=data.section('<',0,0);
  115. if (key.name.find("(")!=-1)
  116. key.name=key.name.section('(',0,0);
  117. m_keys[shortId] = key;
  118. }
  119. break;
  120. case Verify:
  121. data = TQString(data.section("]",1,-1)).stripWhiteSpace();
  122. if (data.startsWith("GOODSIG"))
  123. {
  124. m_result &= SIGNED_BAD_CLEAR;
  125. m_result |= SIGNED_OK;
  126. TQString id = data.section(" ", 1 , 1).right(8);
  127. if (!m_keys.contains(id))
  128. {
  129. m_result |= UNKNOWN;
  130. } else
  131. {
  132. m_signatureKey = m_keys[id];
  133. }
  134. } else
  135. if (data.startsWith("NO_PUBKEY"))
  136. {
  137. m_result &= SIGNED_BAD_CLEAR;
  138. m_result |= UNKNOWN;
  139. } else
  140. if (data.startsWith("BADSIG"))
  141. {
  142. m_result |= SIGNED_BAD;
  143. TQString id = data.section(" ", 1 , 1).right(8);
  144. if (!m_keys.contains(id))
  145. {
  146. m_result |= UNKNOWN;
  147. } else
  148. {
  149. m_signatureKey = m_keys[id];
  150. }
  151. } else
  152. if (data.startsWith("TRUST_ULTIMATE"))
  153. {
  154. m_result &= SIGNED_BAD_CLEAR;
  155. m_result |= TRUSTED;
  156. }
  157. break;
  158. case Sign:
  159. if (data.find("passphrase.enter") != -1)
  160. {
  161. TQCString password;
  162. KeyStruct key = m_keys[m_secretKey];
  163. int result = KPasswordDialog::getPassword(password, i18n("<qt>Enter passphrase for key <b>0x%1</b>, belonging to<br><i>%2&lt;%3&gt;</i>:</qt>").arg(m_secretKey).arg(key.name).arg(key.mail));
  164. if (result == KPasswordDialog::Accepted)
  165. {
  166. procIO->writeStdin(password, true);
  167. password.fill(' ');
  168. }
  169. else
  170. {
  171. m_result |= BAD_PASSPHRASE;
  172. slotProcessExited(procIO);
  173. return;
  174. }
  175. } else
  176. if (data.find("BAD_PASSPHRASE") != -1)
  177. {
  178. m_result |= BAD_PASSPHRASE;
  179. }
  180. break;
  181. }
  182. }
  183. }
  184. void Security::checkValidity(const TQString& filename)
  185. {
  186. m_fileName = filename;
  187. slotCheckValidity();
  188. }
  189. void Security::slotCheckValidity()
  190. {
  191. if (!m_keysRead || m_gpgRunning)
  192. {
  193. TQTimer::singleShot(5, this, TQT_SLOT(slotCheckValidity()));
  194. return;
  195. }
  196. if (m_keys.count() == 0)
  197. {
  198. emit validityResult(-1);
  199. return;
  200. }
  201. m_result = 0;
  202. m_runMode = Verify;
  203. TQFileInfo f(m_fileName);
  204. //check the MD5 sum
  205. TQString md5sum;
  206. const char* c = "";
  207. KMD5 context(c);
  208. TQFile file(m_fileName);
  209. if (file.open(IO_ReadOnly))
  210. {
  211. context.reset();
  212. context.update(TQT_TQIODEVICE_OBJECT(file));
  213. md5sum = context.hexDigest();
  214. file.close();
  215. }
  216. file.setName(f.dirPath() + "/md5sum");
  217. if (file.open(IO_ReadOnly))
  218. {
  219. TQString md5sum_file;
  220. file.readLine(md5sum_file, 50);
  221. if (!md5sum.isEmpty() && !md5sum_file.isEmpty() && md5sum_file.startsWith(md5sum))
  222. m_result |= MD5_OK;
  223. file.close();
  224. }
  225. m_result |= SIGNED_BAD;
  226. m_signatureKey.id = "";
  227. m_signatureKey.name = "";
  228. m_signatureKey.mail = "";
  229. m_signatureKey.trusted = false;
  230. //verify the signature
  231. KProcIO *verifyProcess=new KProcIO();
  232. *verifyProcess<<"gpg"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--verify" << f.dirPath() + "/signature"<< m_fileName;
  233. connect(verifyProcess, TQT_SIGNAL(processExited(TDEProcess *)),this, TQT_SLOT(slotProcessExited(TDEProcess *)));
  234. connect(verifyProcess, TQT_SIGNAL(readReady(KProcIO *)),this, TQT_SLOT(slotDataArrived(KProcIO *)));
  235. if (verifyProcess->start(TDEProcess::NotifyOnExit,true))
  236. m_gpgRunning = true;
  237. else
  238. {
  239. KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and check the validity of the file. Make sure that <i>gpg</i> is installed, otherwise verification of downloaded resources will not be possible.</qt>"));
  240. emit validityResult(0);
  241. delete verifyProcess;
  242. }
  243. }
  244. void Security::signFile(const TQString &fileName)
  245. {
  246. m_fileName = fileName;
  247. slotSignFile();
  248. }
  249. void Security::slotSignFile()
  250. {
  251. if (!m_keysRead || m_gpgRunning)
  252. {
  253. TQTimer::singleShot(5, this, TQT_SLOT(slotSignFile()));
  254. return;
  255. }
  256. TQStringList secretKeys;
  257. for (TQMap<TQString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it)
  258. {
  259. if (it.data().secret)
  260. secretKeys.append(it.key());
  261. }
  262. if (secretKeys.count() == 0)
  263. {
  264. emit fileSigned(-1);
  265. return;
  266. }
  267. m_result = 0;
  268. TQFileInfo f(m_fileName);
  269. //create the MD5 sum
  270. TQString md5sum;
  271. const char* c = "";
  272. KMD5 context(c);
  273. TQFile file(m_fileName);
  274. if (file.open(IO_ReadOnly))
  275. {
  276. context.reset();
  277. context.update(TQT_TQIODEVICE_OBJECT(file));
  278. md5sum = context.hexDigest();
  279. file.close();
  280. }
  281. file.setName(f.dirPath() + "/md5sum");
  282. if (file.open(IO_WriteOnly))
  283. {
  284. TQTextStream stream(&file);
  285. stream << md5sum;
  286. m_result |= MD5_OK;
  287. file.close();
  288. }
  289. if (secretKeys.count() > 1)
  290. {
  291. bool ok;
  292. secretKeys = KInputDialog::getItemList(i18n("Select Signing Key"), i18n("Key used for signing:"), secretKeys, secretKeys[0], false, &ok);
  293. if (ok)
  294. m_secretKey = secretKeys[0];
  295. else
  296. {
  297. emit fileSigned(0);
  298. return;
  299. }
  300. } else
  301. m_secretKey = secretKeys[0];
  302. //verify the signature
  303. KProcIO *signProcess=new KProcIO();
  304. *signProcess<<"gpg"<<"--no-secmem-warning"<<"--status-fd=2"<<"--command-fd=0"<<"--no-tty"<<"--detach-sign" << "-u" << m_secretKey << "-o" << f.dirPath() + "/signature" << m_fileName;
  305. connect(signProcess, TQT_SIGNAL(processExited(TDEProcess *)),this, TQT_SLOT(slotProcessExited(TDEProcess *)));
  306. connect(signProcess, TQT_SIGNAL(readReady(KProcIO *)),this, TQT_SLOT(slotDataArrived(KProcIO *)));
  307. m_runMode = Sign;
  308. if (signProcess->start(TDEProcess::NotifyOnExit,true))
  309. m_gpgRunning = true;
  310. else
  311. {
  312. KMessageBox::error(0L, i18n("<qt>Cannot start <i>gpg</i> and sign the file. Make sure that <i>gpg</i> is installed, otherwise signing of the resources will not be possible.</qt>"));
  313. emit fileSigned(0);
  314. delete signProcess;
  315. }
  316. }
  317. #include "security.moc"