connwrap - initialize gnutls session in cw_connect
[centerim.git] / src / impgp.cc
blobd818082add0891c818cc4a33cadb05dd5d91758d
1 #include "impgp.h"
3 #ifdef HAVE_GPGME
5 #include "icqconf.h"
6 #include "icqface.h"
7 #include "icqcontacts.h"
8 #include "abstracthook.h"
10 impgp pgp;
12 protocolname impgp::opname;
13 string impgp::passphrase[];
15 impgp::impgp() {
16 gpgme_check_version(NULL);
17 if(gpgme_new(&ctx))
18 ctx = 0;
21 impgp::~impgp() {
22 if(ctx)
23 gpgme_release(ctx);
26 string impgp::getkeyinfo(const string &fp, bool secret) {
27 gpgme_key_t key;
28 string r;
30 if(ctx && !gpgme_get_key(ctx, fp.c_str(), &key, secret ? 1 : 0)) {
31 r = key->subkeys->keyid+8;
32 r += ": ";
33 r += key->uids->name;
35 if(key->uids->comment && strlen(key->uids->comment))
36 r += (string) " (" + key->uids->comment + ")";
38 if(key->uids->email && strlen(key->uids->email))
39 r += (string) " <" + key->uids->email + ">";
41 gpgme_key_release(key);
44 return r;
47 vector<string> impgp::getkeys(bool secretonly) {
48 gpgme_key_t key;
49 vector<string> r;
51 if(ctx) {
52 gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
54 if(!gpgme_op_keylist_start(ctx, 0, secretonly ? 1 : 0)) {
55 while(!gpgme_op_keylist_next(ctx, &key)) {
56 r.push_back(key->subkeys->keyid);
57 gpgme_key_release(key);
62 return r;
65 gpgme_error_t impgp::passphrase_cb(void *hook, const char *uidhint,
66 const char *info, int prevbad, int fd) {
68 if(!prevbad) {
69 if(passphrase[opname].empty())
70 passphrase[opname] = conf->getourid(opname).additional["pgppass"];
72 if(passphrase[opname].empty())
73 passphrase[opname] = face.inputstr(_("PGP passphrase required: "), "", '*');
75 } else {
76 face.log((string) "+ [" + conf->getprotocolname(opname) + "] " + _("incorrect PGP passphrase"));
77 // gethook(opname).disconnect(); // sudden disconnect isn't good for Jabber
78 return GPG_ERR_CANCELED;
81 write(fd, passphrase[opname].c_str(), passphrase[opname].size());
82 write(fd, "\n", 1);
84 return 0;
87 string impgp::sign(const string &text, const string &keyid, protocolname pname) {
88 gpgme_data_t in, out;
89 gpgme_key_t key;
90 string r;
91 size_t n;
92 gpgme_error_t err;
94 if(ctx) {
95 gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
96 gpgme_set_textmode(ctx, 0);
97 gpgme_set_armor(ctx, 1);
98 gpgme_set_passphrase_cb(ctx, &passphrase_cb, 0);
99 opname = pname;
101 if(!(err = gpgme_get_key(ctx, keyid.c_str(), &key, 1))) {
102 gpgme_signers_clear(ctx);
103 gpgme_signers_add(ctx, key);
105 if(!(err = gpgme_data_new_from_mem(&in, text.c_str(), text.size(), 0))) {
106 if(!(err = gpgme_data_new(&out))) {
107 if(!(err = gpgme_op_sign(ctx, in, out, GPGME_SIG_MODE_DETACH))) {
108 auto_ptr<char> buf(gpgme_data_release_and_get_mem(out, &n));
109 auto_ptr<char> p(new char[n+1]);
110 strncpy(p.get(), buf.get(), n);
111 p.get()[n] = 0;
112 r = p.get();
113 strip(r);
114 } else {
115 gpgme_data_release(out);
119 gpgme_data_release(in);
122 gpgme_key_release(key);
125 if(err && err != GPG_ERR_CANCELED) {
126 face.log((string) "+ [" + conf->getprotocolname(pname) + "] " +
127 _("PGP sign error: ") + gpgme_strerror(err));
128 // gethook(pname).disconnect(); // sudden disconnect isn't good for Jabber
132 return r;
135 string impgp::verify(string sign, const string &orig) {
136 string r;
137 gpgme_data_t dsign, dorig;
138 gpgme_key_t key;
139 gpgme_verify_result_t vr;
141 if(ctx) {
142 sign = "-----BEGIN PGP SIGNATURE-----\n\n" + sign + "\n-----END PGP SIGNATURE-----\n";
144 if(!gpgme_data_new_from_mem(&dsign, sign.c_str(), sign.size(), 0)) {
145 if(!gpgme_data_new_from_mem(&dorig, orig.c_str(), orig.size(), 0)) {
146 if(!gpgme_op_verify(ctx, dsign, dorig, 0)) {
147 if(vr = gpgme_op_verify_result(ctx)) {
148 if(vr->signatures) {
149 r = vr->signatures->fpr;
151 if(!gpgme_get_key(ctx, r.c_str(), &key, 0)) {
152 r = key->subkeys->keyid;
153 gpgme_key_release(key);
158 gpgme_data_release(dorig);
160 gpgme_data_release(dsign);
164 return r;
167 string impgp::decrypt(string text, protocolname pname) {
168 string r;
169 gpgme_data_t in, out;
170 gpgme_key_t key;
171 gpgme_decrypt_result_t dr;
172 size_t n;
174 if(ctx) {
175 text = "-----BEGIN PGP MESSAGE-----\n\n" + text + "\n-----END PGP MESSAGE-----\n";
176 gpgme_set_passphrase_cb(ctx, &passphrase_cb, 0);
177 opname = pname;
179 if(!gpgme_data_new_from_mem(&in, text.c_str(), text.size(), 0)) {
180 if(!gpgme_data_new(&out)) {
181 if(!gpgme_op_decrypt(ctx, in, out)) {
182 if(dr = gpgme_op_decrypt_result(ctx)) {
185 auto_ptr<char> buf(gpgme_data_release_and_get_mem(out, &n));
186 auto_ptr<char> p(new char[n+1]);
187 strncpy(p.get(), buf.get(), n);
188 p.get()[n] = 0;
189 r = p.get();
190 } else {
191 gpgme_data_release(out);
194 gpgme_data_release(in);
198 return r;
201 string impgp::encrypt(const string &text, const string &keyid, protocolname pname) {
202 string r;
203 gpgme_key_t key;
204 gpgme_data_t in, out;
205 size_t n;
206 gpgme_error_t err;
208 if(ctx) {
209 gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
210 gpgme_set_textmode(ctx, 0);
211 gpgme_set_armor(ctx, 1);
213 if(!(err = gpgme_get_key(ctx, keyid.c_str(), &key, 0))) {
214 gpgme_key_t keys[] = { key, 0 };
216 if(!(err = gpgme_data_new_from_mem(&in, text.c_str(), text.size(), 0))) {
217 if(!(err = gpgme_data_new(&out))) {
218 if(!(err = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out))) {
219 auto_ptr<char> p(gpgme_data_release_and_get_mem(out, &n));
220 r = p.get();
221 strip(r);
222 } else {
223 gpgme_data_release(out);
226 gpgme_data_release(in);
228 gpgme_key_release(key);
232 if(err && err != GPG_ERR_CANCELED) {
233 face.log((string) "+ [" + conf->getprotocolname(pname) + "] " +
234 _("PGP encrypt error: ") + gpgme_strerror(err));
235 gethook(pname).disconnect();
238 return r;
241 bool impgp::havekey(const string &keyid) const {
242 gpgme_key_t key;
243 bool r = !gpgme_get_key(ctx, keyid.c_str(), &key, 0);
244 if(r) gpgme_key_release(key);
245 return r;
248 bool impgp::enabled(protocolname pname) const {
249 return gethook(pname).getCapabs().count(hookcapab::pgp)
250 && !conf->getourid(pname).additional["pgpkey"].empty();
253 bool impgp::enabled(const imcontact &ic) const {
254 bool r = false;
255 icqcontact *c;
257 if(c = clist.get(ic))
258 r = enabled(ic.pname)
259 && c->getusepgpkey()
260 && !c->getpgpkey().empty()
261 && havekey(c->getpgpkey());
263 return r;
266 void impgp::clearphrase(protocolname p) {
267 passphrase[p] = "";
270 void impgp::strip(string &r) {
271 int n;
273 if((n = r.find("\n\n")) != -1)
274 r.erase(0, n+2);
276 if((n = r.rfind("\n")) != -1)
277 r.erase(n);
279 if((n = r.rfind("\n")) != -1)
280 r.erase(n);
283 #endif