00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
#include <qfile.h>
00018
#include <qfileinfo.h>
00019
#include <qstringlist.h>
00020
#include <qtimer.h>
00021
00022
00023
#include <kdebug.h>
00024
#include <kinputdialog.h>
00025
#include <klocale.h>
00026
#include <kmdcodec.h>
00027
#include <kmessagebox.h>
00028
#include <kpassdlg.h>
00029
#include <kprocio.h>
00030
00031
00032
#include "security.h"
00033
00034
using namespace KNS;
00035
00036 Security::Security()
00037 {
00038 m_keysRead =
false;
00039 m_gpgRunning =
false;
00040 readKeys();
00041 readSecretKeys();
00042 }
00043
00044
00045 Security::~Security()
00046 {
00047 }
00048
00049
void Security::readKeys()
00050 {
00051
if (m_gpgRunning)
00052 {
00053 QTimer::singleShot(5,
this, SLOT(readKeys()));
00054
return;
00055 }
00056 m_runMode = List;
00057 m_keys.clear();
00058 KProcIO *readProcess=
new KProcIO();
00059 *readProcess <<
"gpg"<<
"--no-secmem-warning"<<
"--no-tty"<<
"--with-colon"<<
"--list-keys";
00060 connect(readProcess, SIGNAL(processExited(KProcess *)),
this, SLOT(slotProcessExited(KProcess *)));
00061 connect(readProcess, SIGNAL(readReady(KProcIO *)) ,
this, SLOT(slotDataArrived(KProcIO *)));
00062
if (!readProcess->start(KProcess::NotifyOnExit,
true))
00063 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>"));
00064
else
00065 m_gpgRunning =
true;
00066 }
00067
00068
void Security::readSecretKeys()
00069 {
00070
if (m_gpgRunning)
00071 {
00072 QTimer::singleShot(5,
this, SLOT(readSecretKeys()));
00073
return;
00074 }
00075 m_runMode = ListSecret;
00076 KProcIO *readProcess=
new KProcIO();
00077 *readProcess <<
"gpg"<<
"--no-secmem-warning"<<
"--no-tty"<<
"--with-colon"<<
"--list-secret-keys";
00078 connect(readProcess, SIGNAL(processExited(KProcess *)),
this, SLOT(slotProcessExited(KProcess *)));
00079 connect(readProcess, SIGNAL(readReady(KProcIO *)) ,
this, SLOT(slotDataArrived(KProcIO *)));
00080
if (readProcess->start(KProcess::NotifyOnExit,
true))
00081 m_gpgRunning =
true;
00082 }
00083
00084
void Security::slotProcessExited(KProcess *process)
00085 {
00086
switch (m_runMode)
00087 {
00088
case ListSecret:
00089 m_keysRead =
true;
00090
break;
00091
case Verify: emit validityResult(m_result);
00092
break;
00093
case Sign: emit fileSigned(m_result);
00094
break;
00095
00096 }
00097 m_gpgRunning =
false;
00098
delete process;
00099 }
00100
00101
void Security::slotDataArrived(KProcIO *procIO)
00102 {
00103
QString data;
00104
while (procIO->readln(data,
true) != -1)
00105 {
00106
switch (m_runMode)
00107 {
00108
case List:
00109
case ListSecret:
00110
if (data.startsWith(
"pub") || data.startsWith(
"sec"))
00111 {
00112 KeyStruct key;
00113
if (data.startsWith(
"pub"))
00114 key.secret =
false;
00115
else
00116 key.secret =
true;
00117
QStringList line = QStringList::split(
":", data,
true);
00118 key.id = line[4];
00119
QString shortId = key.id.right(8);
00120
QString trustStr = line[1];
00121 key.trusted =
false;
00122
if (trustStr ==
"u" || trustStr ==
"f")
00123 key.trusted =
true;
00124 data = line[9];
00125 key.mail=data.section(
'<', -1, -1);
00126 key.mail.truncate(key.mail.length() - 1);
00127 key.name=data.section(
'<',0,0);
00128
if (key.name.find(
"(")!=-1)
00129 key.name=key.name.section(
'(',0,0);
00130 m_keys[shortId] = key;
00131 }
00132
break;
00133
case Verify:
00134 data = data.section(
"]",1,-1).stripWhiteSpace();
00135
if (data.startsWith(
"GOODSIG"))
00136 {
00137 m_result &= SIGNED_BAD_CLEAR;
00138 m_result |= SIGNED_OK;
00139
QString id = data.section(
" ", 1 , 1).right(8);
00140
if (!m_keys.contains(
id))
00141 {
00142 m_result |= UNKNOWN;
00143 }
else
00144 {
00145 m_signatureKey = m_keys[
id];
00146 }
00147 }
else
00148
if (data.startsWith(
"NO_PUBKEY"))
00149 {
00150 m_result &= SIGNED_BAD_CLEAR;
00151 m_result |= UNKNOWN;
00152 }
else
00153
if (data.startsWith(
"BADSIG"))
00154 {
00155 m_result |= SIGNED_BAD;
00156
QString id = data.section(
" ", 1 , 1).right(8);
00157
if (!m_keys.contains(
id))
00158 {
00159 m_result |= UNKNOWN;
00160 }
else
00161 {
00162 m_signatureKey = m_keys[
id];
00163 }
00164 }
else
00165
if (data.startsWith(
"TRUST_ULTIMATE"))
00166 {
00167 m_result &= SIGNED_BAD_CLEAR;
00168 m_result |= TRUSTED;
00169 }
00170
break;
00171
00172
case Sign:
00173
if (data.find(
"passphrase.enter") != -1)
00174 {
00175
QCString password;
00176 KeyStruct key = m_keys[m_secretKey];
00177
int result = KPasswordDialog::getPassword(password, i18n(
"<qt>Enter passphrase for key <b>0x%1</b>, belonging to<br><i>%2<%3></i>:</qt>").arg(m_secretKey).arg(key.name).arg(key.mail));
00178
if (result == KPasswordDialog::Accepted)
00179 {
00180 procIO->writeStdin(password,
true);
00181 password.fill(
' ');
00182 }
00183
else
00184 {
00185 m_result |= BAD_PASSPHRASE;
00186 slotProcessExited(procIO);
00187
return;
00188 }
00189 }
else
00190
if (data.find(
"BAD_PASSPHRASE") != -1)
00191 {
00192 m_result |= BAD_PASSPHRASE;
00193 }
00194
break;
00195 }
00196 }
00197 }
00198
00199
void Security::checkValidity(
const QString& filename)
00200 {
00201 m_fileName = filename;
00202 slotCheckValidity();
00203 }
00204
00205
void Security::slotCheckValidity()
00206 {
00207
if (!m_keysRead || m_gpgRunning)
00208 {
00209 QTimer::singleShot(5,
this, SLOT(slotCheckValidity()));
00210
return;
00211 }
00212
if (m_keys.count() == 0)
00213 {
00214 emit validityResult(-1);
00215
return;
00216 }
00217
00218 m_result = 0;
00219 m_runMode = Verify;
00220
QFileInfo f(m_fileName);
00221
00222
QString md5sum;
00223
const char* c =
"";
00224 KMD5 context(c);
00225
QFile file(m_fileName);
00226
if (file.open(IO_ReadOnly))
00227 {
00228 context.reset();
00229 context.update(file);
00230 md5sum = context.hexDigest();
00231 file.close();
00232 }
00233 file.setName(f.dirPath() +
"/md5sum");
00234
if (file.open(IO_ReadOnly))
00235 {
00236
QString md5sum_file;
00237 file.readLine(md5sum_file, 50);
00238
if (!md5sum.isEmpty() && !md5sum_file.isEmpty() && md5sum_file.startsWith(md5sum))
00239 m_result |= MD5_OK;
00240 file.close();
00241 }
00242 m_result |= SIGNED_BAD;
00243 m_signatureKey.id =
"";
00244 m_signatureKey.name =
"";
00245 m_signatureKey.mail =
"";
00246 m_signatureKey.trusted =
false;
00247
00248
00249 KProcIO *verifyProcess=
new KProcIO();
00250 *verifyProcess<<
"gpg"<<
"--no-secmem-warning"<<
"--status-fd=2"<<
"--command-fd=0"<<
"--verify" << f.dirPath() +
"/signature"<< m_fileName;
00251 connect(verifyProcess, SIGNAL(processExited(KProcess *)),
this, SLOT(slotProcessExited(KProcess *)));
00252 connect(verifyProcess, SIGNAL(readReady(KProcIO *)),
this, SLOT(slotDataArrived(KProcIO *)));
00253
if (verifyProcess->start(KProcess::NotifyOnExit,
true))
00254 m_gpgRunning =
true;
00255
else
00256 {
00257 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>"));
00258 emit validityResult(0);
00259
delete verifyProcess;
00260 }
00261 }
00262
00263
void Security::signFile(
const QString &fileName)
00264 {
00265 m_fileName = fileName;
00266 slotSignFile();
00267 }
00268
00269
void Security::slotSignFile()
00270 {
00271
if (!m_keysRead || m_gpgRunning)
00272 {
00273 QTimer::singleShot(5,
this, SLOT(slotSignFile()));
00274
return;
00275 }
00276
00277
QStringList secretKeys;
00278
for (
QMap<QString, KeyStruct>::Iterator it = m_keys.begin(); it != m_keys.end(); ++it)
00279 {
00280
if (it.data().secret)
00281 secretKeys.append(it.key());
00282 }
00283
00284
if (secretKeys.count() == 0)
00285 {
00286 emit fileSigned(-1);
00287
return;
00288 }
00289
00290 m_result = 0;
00291
QFileInfo f(m_fileName);
00292
00293
00294
QString md5sum;
00295
const char* c =
"";
00296 KMD5 context(c);
00297
QFile file(m_fileName);
00298
if (file.open(IO_ReadOnly))
00299 {
00300 context.reset();
00301 context.update(file);
00302 md5sum = context.hexDigest();
00303 file.close();
00304 }
00305 file.setName(f.dirPath() +
"/md5sum");
00306
if (file.open(IO_WriteOnly))
00307 {
00308
QTextStream stream(&file);
00309 stream << md5sum;
00310 m_result |= MD5_OK;
00311 file.close();
00312 }
00313
00314
if (secretKeys.count() > 1)
00315 {
00316
bool ok;
00317 secretKeys = KInputDialog::getItemList(i18n(
"Select Signing Key"), i18n(
"Key used for signing:"), secretKeys, secretKeys[0],
false, &ok);
00318
if (ok)
00319 m_secretKey = secretKeys[0];
00320
else
00321 {
00322 emit fileSigned(0);
00323
return;
00324 }
00325 }
else
00326 m_secretKey = secretKeys[0];
00327
00328
00329 KProcIO *signProcess=
new KProcIO();
00330 *signProcess<<
"gpg"<<
"--no-secmem-warning"<<
"--status-fd=2"<<
"--command-fd=0"<<
"--no-tty"<<
"--detach-sign" <<
"-u" << m_secretKey <<
"-o" << f.dirPath() +
"/signature" << m_fileName;
00331 connect(signProcess, SIGNAL(processExited(KProcess *)),
this, SLOT(slotProcessExited(KProcess *)));
00332 connect(signProcess, SIGNAL(readReady(KProcIO *)),
this, SLOT(slotDataArrived(KProcIO *)));
00333 m_runMode = Sign;
00334
if (signProcess->start(KProcess::NotifyOnExit,
true))
00335 m_gpgRunning =
true;
00336
else
00337 {
00338 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>"));
00339 emit fileSigned(0);
00340
delete signProcess;
00341 }
00342 }
00343
00344
#include "security.moc"