File indexing completed on 2024-05-05 04:45:05

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