File indexing completed on 2025-01-12 04:19:46
0001 /* 0002 * Copyright (C) 2003-2008 Justin Karneges <justin@affinix.com> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2.1 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Lesser General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Lesser General Public 0015 * License along with this library; if not, write to the Free Software 0016 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 0017 */ 0018 0019 #include "mymessagecontext.h" 0020 #include "mykeystorelist.h" 0021 #include "mypgpkeycontext.h" 0022 #include "utils.h" 0023 0024 using namespace QCA; 0025 0026 namespace gpgQCAPlugin { 0027 0028 MyMessageContext::MyMessageContext(MyOpenPGPContext *_sms, Provider *p) 0029 : MessageContext(p, QStringLiteral("pgpmsg")) 0030 , sms(_sms) 0031 , op(Sign) 0032 , signMode(SecureMessage::Detached) 0033 , format(SecureMessage::Ascii) 0034 , wrote(0) 0035 , ok(false) 0036 , wasSigned(false) 0037 , op_err(GpgOp::ErrorUnknown) 0038 , gpg(find_bin()) 0039 , _finished(false) 0040 { 0041 connect(&gpg, &GpgOp::readyRead, this, &MyMessageContext::gpg_readyRead); 0042 connect(&gpg, &GpgOp::bytesWritten, this, &MyMessageContext::gpg_bytesWritten); 0043 connect(&gpg, &GpgOp::finished, this, &MyMessageContext::gpg_finished); 0044 connect(&gpg, &GpgOp::needPassphrase, this, &MyMessageContext::gpg_needPassphrase); 0045 connect(&gpg, &GpgOp::needCard, this, &MyMessageContext::gpg_needCard); 0046 connect(&gpg, &GpgOp::readyReadDiagnosticText, this, &MyMessageContext::gpg_readyReadDiagnosticText); 0047 0048 connect(&asker, &QCA::PasswordAsker::responseReady, this, &MyMessageContext::asker_responseReady); 0049 connect(&tokenAsker, &QCA::TokenAsker::responseReady, this, &MyMessageContext::tokenAsker_responseReady); 0050 } 0051 0052 Provider::Context *MyMessageContext::clone() const 0053 { 0054 return nullptr; 0055 } 0056 0057 bool MyMessageContext::canSignMultiple() const 0058 { 0059 return false; 0060 } 0061 0062 SecureMessage::Type MyMessageContext::type() const 0063 { 0064 return SecureMessage::OpenPGP; 0065 } 0066 0067 void MyMessageContext::reset() 0068 { 0069 wrote = 0; 0070 ok = false; 0071 wasSigned = false; 0072 } 0073 0074 void MyMessageContext::setupEncrypt(const SecureMessageKeyList &keys) 0075 { 0076 recipIds.clear(); 0077 for (int n = 0; n < keys.count(); ++n) 0078 recipIds += keys[n].pgpPublicKey().keyId(); 0079 } 0080 0081 void MyMessageContext::setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool, bool) 0082 { 0083 signerId = keys.first().pgpSecretKey().keyId(); 0084 signMode = m; 0085 } 0086 0087 void MyMessageContext::setupVerify(const QByteArray &detachedSig) 0088 { 0089 sig = detachedSig; 0090 } 0091 0092 void MyMessageContext::start(SecureMessage::Format f, Operation op) 0093 { 0094 _finished = false; 0095 format = f; 0096 this->op = op; 0097 0098 if (getProperty(QStringLiteral("pgp-always-trust")).toBool()) 0099 gpg.setAlwaysTrust(true); 0100 0101 if (format == SecureMessage::Ascii) 0102 gpg.setAsciiFormat(true); 0103 else 0104 gpg.setAsciiFormat(false); 0105 0106 if (op == Encrypt) { 0107 gpg.doEncrypt(recipIds); 0108 } else if (op == Decrypt) { 0109 gpg.doDecrypt(); 0110 } else if (op == Sign) { 0111 if (signMode == SecureMessage::Message) { 0112 gpg.doSign(signerId); 0113 } else if (signMode == SecureMessage::Clearsign) { 0114 gpg.doSignClearsign(signerId); 0115 } else // SecureMessage::Detached 0116 { 0117 gpg.doSignDetached(signerId); 0118 } 0119 } else if (op == Verify) { 0120 if (!sig.isEmpty()) 0121 gpg.doVerifyDetached(sig); 0122 else 0123 gpg.doDecrypt(); 0124 } else if (op == SignAndEncrypt) { 0125 gpg.doSignAndEncrypt(signerId, recipIds); 0126 } 0127 } 0128 0129 void MyMessageContext::update(const QByteArray &in) 0130 { 0131 gpg.write(in); 0132 // this->in.append(in); 0133 } 0134 0135 QByteArray MyMessageContext::read() 0136 { 0137 const QByteArray a = out; 0138 out.clear(); 0139 return a; 0140 } 0141 0142 int MyMessageContext::written() 0143 { 0144 int x = wrote; 0145 wrote = 0; 0146 return x; 0147 } 0148 0149 void MyMessageContext::end() 0150 { 0151 gpg.endWrite(); 0152 } 0153 0154 void MyMessageContext::seterror() 0155 { 0156 gpg.reset(); 0157 _finished = true; 0158 ok = false; 0159 op_err = GpgOp::ErrorUnknown; 0160 } 0161 0162 void MyMessageContext::complete() 0163 { 0164 _finished = true; 0165 0166 dtext = gpg.readDiagnosticText(); 0167 0168 ok = gpg.success(); 0169 if (ok) { 0170 if (op == Sign && signMode == SecureMessage::Detached) 0171 sig = gpg.read(); 0172 else 0173 out = gpg.read(); 0174 } 0175 0176 if (ok) { 0177 if (gpg.wasSigned()) { 0178 const QString signerId = gpg.signerId(); 0179 const QDateTime ts = gpg.timestamp(); 0180 const GpgOp::VerifyResult vr = gpg.verifyResult(); 0181 0182 SecureMessageSignature::IdentityResult ir; 0183 Validity v; 0184 if (vr == GpgOp::VerifyGood) { 0185 ir = SecureMessageSignature::Valid; 0186 v = ValidityGood; 0187 } else if (vr == GpgOp::VerifyBad) { 0188 ir = SecureMessageSignature::InvalidSignature; 0189 v = ValidityGood; // good key, bad sig 0190 } else // GpgOp::VerifyNoKey 0191 { 0192 ir = SecureMessageSignature::NoKey; 0193 v = ErrorValidityUnknown; 0194 } 0195 0196 SecureMessageKey key; 0197 PGPKey pub = publicKeyFromId(signerId); 0198 if (pub.isNull()) { 0199 MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); 0200 kc->_props.keyId = signerId; 0201 pub.change(kc); 0202 } 0203 key.setPGPPublicKey(pub); 0204 0205 signer = SecureMessageSignature(ir, v, key, ts); 0206 wasSigned = true; 0207 } 0208 } else 0209 op_err = gpg.errorCode(); 0210 } 0211 0212 bool MyMessageContext::finished() const 0213 { 0214 return _finished; 0215 } 0216 0217 bool MyMessageContext::waitForFinished(int msecs) 0218 { 0219 // FIXME 0220 Q_UNUSED(msecs); 0221 MyKeyStoreList *keyStoreList = MyKeyStoreList::instance(); 0222 0223 while (true) { 0224 // TODO: handle token prompt events 0225 0226 GpgOp::Event e = gpg.waitForEvent(-1); 0227 if (e.type == GpgOp::Event::NeedPassphrase) { 0228 // TODO 0229 0230 QString keyId; 0231 PGPKey sec = secretKeyFromId(e.keyId); 0232 if (!sec.isNull()) 0233 keyId = sec.keyId(); 0234 else 0235 keyId = e.keyId; 0236 QStringList out; 0237 out += escape_string(QStringLiteral("qca-gnupg-1")); 0238 out += escape_string(keyId); 0239 QString serialized = out.join(QStringLiteral(":")); 0240 0241 KeyStoreEntry kse; 0242 KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized); 0243 if (c) 0244 kse.change(c); 0245 0246 asker.ask(Event::StylePassphrase, 0247 KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), 0248 kse, 0249 nullptr); 0250 asker.waitForResponse(); 0251 0252 if (!asker.accepted()) { 0253 seterror(); 0254 return true; 0255 } 0256 0257 gpg.submitPassphrase(asker.password()); 0258 } else if (e.type == GpgOp::Event::NeedCard) { 0259 tokenAsker.ask(KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), 0260 KeyStoreEntry(), 0261 nullptr); 0262 0263 if (!tokenAsker.accepted()) { 0264 seterror(); 0265 return true; 0266 } 0267 0268 gpg.cardOkay(); 0269 } else if (e.type == GpgOp::Event::Finished) 0270 break; 0271 } 0272 0273 complete(); 0274 return true; 0275 } 0276 0277 bool MyMessageContext::success() const 0278 { 0279 return ok; 0280 } 0281 0282 SecureMessage::Error MyMessageContext::errorCode() const 0283 { 0284 SecureMessage::Error e = SecureMessage::ErrorUnknown; 0285 if (op_err == GpgOp::ErrorProcess) 0286 e = SecureMessage::ErrorUnknown; 0287 else if (op_err == GpgOp::ErrorPassphrase) 0288 e = SecureMessage::ErrorPassphrase; 0289 else if (op_err == GpgOp::ErrorFormat) 0290 e = SecureMessage::ErrorFormat; 0291 else if (op_err == GpgOp::ErrorSignerExpired) 0292 e = SecureMessage::ErrorSignerExpired; 0293 else if (op_err == GpgOp::ErrorSignerRevoked) 0294 e = SecureMessage::ErrorSignerRevoked; 0295 else if (op_err == GpgOp::ErrorSignatureExpired) 0296 e = SecureMessage::ErrorSignatureExpired; 0297 else if (op_err == GpgOp::ErrorEncryptExpired) 0298 e = SecureMessage::ErrorEncryptExpired; 0299 else if (op_err == GpgOp::ErrorEncryptRevoked) 0300 e = SecureMessage::ErrorEncryptRevoked; 0301 else if (op_err == GpgOp::ErrorEncryptUntrusted) 0302 e = SecureMessage::ErrorEncryptUntrusted; 0303 else if (op_err == GpgOp::ErrorEncryptInvalid) 0304 e = SecureMessage::ErrorEncryptInvalid; 0305 else if (op_err == GpgOp::ErrorDecryptNoKey) 0306 e = SecureMessage::ErrorUnknown; 0307 else if (op_err == GpgOp::ErrorUnknown) 0308 e = SecureMessage::ErrorUnknown; 0309 return e; 0310 } 0311 0312 QByteArray MyMessageContext::signature() const 0313 { 0314 return sig; 0315 } 0316 0317 QString MyMessageContext::hashName() const 0318 { 0319 // TODO 0320 return QStringLiteral("sha1"); 0321 } 0322 0323 SecureMessageSignatureList MyMessageContext::signers() const 0324 { 0325 SecureMessageSignatureList list; 0326 if (ok && wasSigned) 0327 list += signer; 0328 return list; 0329 } 0330 0331 QString MyMessageContext::diagnosticText() const 0332 { 0333 return dtext; 0334 } 0335 0336 void MyMessageContext::gpg_readyRead() 0337 { 0338 emit updated(); 0339 } 0340 0341 void MyMessageContext::gpg_bytesWritten(int bytes) 0342 { 0343 wrote += bytes; 0344 } 0345 0346 void MyMessageContext::gpg_finished() 0347 { 0348 complete(); 0349 emit updated(); 0350 } 0351 0352 void MyMessageContext::gpg_needPassphrase(const QString &in_keyId) 0353 { 0354 // FIXME: copied from above, clean up later 0355 0356 QString keyId; 0357 PGPKey sec = secretKeyFromId(in_keyId); 0358 if (!sec.isNull()) 0359 keyId = sec.keyId(); 0360 else 0361 keyId = in_keyId; 0362 // emit keyStoreList->storeNeedPassphrase(0, 0, keyId); 0363 QStringList out; 0364 out += escape_string(QStringLiteral("qca-gnupg-1")); 0365 out += escape_string(keyId); 0366 QString serialized = out.join(QStringLiteral(":")); 0367 0368 KeyStoreEntry kse; 0369 MyKeyStoreList *keyStoreList = MyKeyStoreList::instance(); 0370 KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized); 0371 if (c) 0372 kse.change(c); 0373 0374 asker.ask(Event::StylePassphrase, 0375 KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), 0376 kse, 0377 nullptr); 0378 } 0379 0380 void MyMessageContext::gpg_needCard() 0381 { 0382 MyKeyStoreList *keyStoreList = MyKeyStoreList::instance(); 0383 tokenAsker.ask( 0384 KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), KeyStoreEntry(), nullptr); 0385 } 0386 0387 void MyMessageContext::gpg_readyReadDiagnosticText() 0388 { 0389 // TODO ? 0390 } 0391 0392 void MyMessageContext::asker_responseReady() 0393 { 0394 if (!asker.accepted()) { 0395 seterror(); 0396 emit updated(); 0397 return; 0398 } 0399 0400 const SecureArray a = asker.password(); 0401 gpg.submitPassphrase(a); 0402 } 0403 0404 void MyMessageContext::tokenAsker_responseReady() 0405 { 0406 if (!tokenAsker.accepted()) { 0407 seterror(); 0408 emit updated(); 0409 return; 0410 } 0411 0412 gpg.cardOkay(); 0413 } 0414 0415 } // end namespace gpgQCAPlugin