1 #include "mypgpkeycontext.h"
2 #include "gpgop.h"
3 #include "utils.h"
4 #include <QDir>
5 #include <QTemporaryFile>
6 
7 using namespace QCA;
8 
9 namespace gpgQCAPlugin {
10 
MyPGPKeyContext(Provider * p)11 MyPGPKeyContext::MyPGPKeyContext(Provider *p)
12     : PGPKeyContext(p)
13 {
14     // zero out the props
15     _props.isSecret  = false;
16     _props.inKeyring = true;
17     _props.isTrusted = false;
18 }
19 
clone() const20 Provider::Context *MyPGPKeyContext::clone() const
21 {
22     return new MyPGPKeyContext(*this);
23 }
24 
props() const25 const PGPKeyContextProps *MyPGPKeyContext::props() const
26 {
27     return &_props;
28 }
29 
toBinary() const30 QByteArray MyPGPKeyContext::toBinary() const
31 {
32     if (_props.inKeyring) {
33         GpgOp gpg(find_bin());
34         gpg.setAsciiFormat(false);
35         gpg.doExport(_props.keyId);
36         gpg_waitForFinished(&gpg);
37         gpg_keyStoreLog(gpg.readDiagnosticText());
38         if (!gpg.success())
39             return QByteArray();
40         return gpg.read();
41     } else
42         return cacheExportBinary;
43 }
44 
fromBinary(const QByteArray & a)45 ConvertResult MyPGPKeyContext::fromBinary(const QByteArray &a)
46 {
47     GpgOp::Key key;
48     bool       sec = false;
49 
50     // temporary keyrings
51     QString pubname, secname;
52 
53     QTemporaryFile pubtmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg"));
54     if (!pubtmp.open())
55         return ErrorDecode;
56 
57     QTemporaryFile sectmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg"));
58     if (!sectmp.open())
59         return ErrorDecode;
60 
61     pubname = pubtmp.fileName();
62     secname = sectmp.fileName();
63 
64     // we turn off autoRemove so that we can close the files
65     //   without them getting deleted
66     pubtmp.setAutoRemove(false);
67     sectmp.setAutoRemove(false);
68     pubtmp.close();
69     sectmp.close();
70 
71     // import key into temporary keyring
72     GpgOp gpg(find_bin());
73     gpg.setKeyrings(pubname, secname);
74     gpg.doImport(a);
75     gpg_waitForFinished(&gpg);
76     gpg_keyStoreLog(gpg.readDiagnosticText());
77     // comment this out.  apparently gpg will report failure for
78     //   an import if there are trust issues, even though the
79     //   key actually did get imported
80     /*if(!gpg.success())
81       {
82       cleanup_temp_keyring(pubname);
83       cleanup_temp_keyring(secname);
84       return ErrorDecode;
85       }*/
86 
87     // now extract the key from gpg like normal
88 
89     // is it a public key?
90     gpg.doPublicKeys();
91     gpg_waitForFinished(&gpg);
92     gpg_keyStoreLog(gpg.readDiagnosticText());
93     if (!gpg.success()) {
94         cleanup_temp_keyring(pubname);
95         cleanup_temp_keyring(secname);
96         return ErrorDecode;
97     }
98 
99     const GpgOp::KeyList pubkeys = gpg.keys();
100     if (!pubkeys.isEmpty()) {
101         key = pubkeys.first();
102     } else {
103         // is it a secret key?
104         gpg.doSecretKeys();
105         gpg_waitForFinished(&gpg);
106         gpg_keyStoreLog(gpg.readDiagnosticText());
107         if (!gpg.success()) {
108             cleanup_temp_keyring(pubname);
109             cleanup_temp_keyring(secname);
110             return ErrorDecode;
111         }
112 
113         const GpgOp::KeyList seckeys = gpg.keys();
114         if (!seckeys.isEmpty()) {
115             key = seckeys.first();
116             sec = true;
117         } else {
118             // no keys found
119             cleanup_temp_keyring(pubname);
120             cleanup_temp_keyring(secname);
121             return ErrorDecode;
122         }
123     }
124 
125     // export binary/ascii and cache
126 
127     gpg.setAsciiFormat(false);
128     gpg.doExport(key.keyItems.first().id);
129     gpg_waitForFinished(&gpg);
130     gpg_keyStoreLog(gpg.readDiagnosticText());
131     if (!gpg.success()) {
132         cleanup_temp_keyring(pubname);
133         cleanup_temp_keyring(secname);
134         return ErrorDecode;
135     }
136     cacheExportBinary = gpg.read();
137 
138     gpg.setAsciiFormat(true);
139     gpg.doExport(key.keyItems.first().id);
140     gpg_waitForFinished(&gpg);
141     gpg_keyStoreLog(gpg.readDiagnosticText());
142     if (!gpg.success()) {
143         cleanup_temp_keyring(pubname);
144         cleanup_temp_keyring(secname);
145         return ErrorDecode;
146     }
147     cacheExportAscii = QString::fromLocal8Bit(gpg.read());
148 
149     // all done
150 
151     cleanup_temp_keyring(pubname);
152     cleanup_temp_keyring(secname);
153 
154     set(key, sec, false, false);
155     return ConvertGood;
156 }
157 
toAscii() const158 QString MyPGPKeyContext::toAscii() const
159 {
160     if (_props.inKeyring) {
161         GpgOp gpg(find_bin());
162         gpg.setAsciiFormat(true);
163         gpg.doExport(_props.keyId);
164         gpg_waitForFinished(&gpg);
165         gpg_keyStoreLog(gpg.readDiagnosticText());
166         if (!gpg.success())
167             return QString();
168         return QString::fromLocal8Bit(gpg.read());
169     } else {
170         return cacheExportAscii;
171     }
172 }
173 
fromAscii(const QString & s)174 ConvertResult MyPGPKeyContext::fromAscii(const QString &s)
175 {
176     // GnuPG does ascii/binary detection for imports, so for
177     //   simplicity we consider an ascii import to just be a
178     //   binary import that happens to be comprised of ascii
179     return fromBinary(s.toLocal8Bit());
180 }
181 
set(const GpgOp::Key & i,bool isSecret,bool inKeyring,bool isTrusted)182 void MyPGPKeyContext::set(const GpgOp::Key &i, bool isSecret, bool inKeyring, bool isTrusted)
183 {
184     const GpgOp::KeyItem &ki = i.keyItems.first();
185 
186     _props.keyId          = ki.id;
187     _props.userIds        = i.userIds;
188     _props.isSecret       = isSecret;
189     _props.creationDate   = ki.creationDate;
190     _props.expirationDate = ki.expirationDate;
191     _props.fingerprint    = ki.fingerprint.toLower();
192     _props.inKeyring      = inKeyring;
193     _props.isTrusted      = isTrusted;
194 }
195 
cleanup_temp_keyring(const QString & name)196 void MyPGPKeyContext::cleanup_temp_keyring(const QString &name)
197 {
198     QFile::remove(name);
199     QFile::remove(name + QLatin1Char('~')); // remove possible backup file
200 }
201 
202 } // end namespace gpgQCAPlugin
203