void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error) { GIOErrorEnum errcode; /* XXX This list is incomplete. Add cases as needed. */ switch (gpg_error) { /* special case - shouldn't be here */ case GPG_ERR_NO_ERROR: g_return_if_reached (); /* special case - abort on out-of-memory */ case GPG_ERR_ENOMEM: g_error ("%s: %s", gpgme_strsource (gpg_error), gpgme_strerror (gpg_error)); case GPG_ERR_INV_VALUE: errcode = G_IO_ERROR_INVALID_ARGUMENT; break; default: errcode = G_IO_ERROR_FAILED; break; } g_set_error (error, G_IO_ERROR, errcode, "%s: %s", gpgme_strsource (gpg_error), gpgme_strerror (gpg_error)); }
gboolean p_gpg_addkey(const char *const jid, const char *const keyid) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return FALSE; } gpgme_key_t key = NULL; error = gpgme_get_key(ctx, keyid, &key, 0); gpgme_release(ctx); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return FALSE; } // save to public key file g_key_file_set_string(pubkeyfile, jid, "keyid", keyid); _save_pubkeys(); // update in memory pubkeys list ProfPGPPubKeyId *pubkeyid = malloc(sizeof(ProfPGPPubKeyId)); pubkeyid->id = strdup(keyid); pubkeyid->received = FALSE; g_hash_table_replace(pubkeys, strdup(jid), pubkeyid); gpgme_key_unref(key); return TRUE; }
gboolean p_gpg_valid_key(const char *const keyid, char **err_str) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); *err_str = strdup(gpgme_strerror(error)); return FALSE; } gpgme_key_t key = NULL; error = gpgme_get_key(ctx, keyid, &key, 1); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); *err_str = strdup(gpgme_strerror(error)); gpgme_release(ctx); return FALSE; } if (key == NULL) { *err_str = strdup("Unknown error"); gpgme_release(ctx); return FALSE; } gpgme_release(ctx); gpgme_key_unref(key); return TRUE; }
/* ------------------ * check if a key is locally available * ------------------ */ int is_key_available(const char* fpr,int secret, int servermode, char** userid) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_key_t key; gpgme_key_t key_arr[2]; gpgme_keylist_mode_t current_keylist_mode; key_arr[0] = NULL; key_arr[1] = NULL; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return FALSE; } // set to server search mode if servermode == TRUE if (servermode == TRUE) { purple_debug_info(PLUGIN_ID,"set keylist mode to server\n"); current_keylist_mode = gpgme_get_keylist_mode(ctx); gpgme_set_keylist_mode(ctx,(current_keylist_mode | GPGME_KEYLIST_MODE_EXTERN) &(~GPGME_KEYLIST_MODE_LOCAL)); } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,secret); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return FALSE; } // if we have parameter, tell caller about userid if (userid != NULL) { *userid = g_strdup(key->uids->uid); } // import key key_arr[0] = key; error = gpgme_op_import_keys (ctx, key_arr); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_import_keys failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return FALSE; } // close gpgme connection gpgme_release (ctx); // we got the key, YEAH :) return TRUE; }
/* ------------------ * get ascii armored public key * FREE MEMORY AFTER USAGE OF RETURN VALUE! * ------------------ */ char* get_key_armored(const char* fpr) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_data_t key_data; gpgme_key_t key; gpgme_key_t key_arr[2]; key_arr[0] = key_arr[1] = NULL; size_t len = 0; char* key_str = NULL; char* key_str_dup = NULL; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,0); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } key_arr[0] = key; // create data containers gpgme_data_new(&key_data); // export key gpgme_set_armor(ctx,1); error = gpgme_op_export_keys (ctx, key_arr, 0, key_data); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_export_keys failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers key_str = gpgme_data_release_and_get_mem(key_data,&len); if (key_str != NULL) { key_str[len] = 0; key_str_dup = g_strdup(key_str); } gpgme_free(key_str); // close gpgme connection gpgme_release (ctx); // we got the key, YEAH :) return key_str_dup; }
/* ------------------ * verify a signed string with the key found with fingerprint fpr * FREE MEMORY AFTER USAGE OF RETURN VALUE! * ------------------ */ static char* verify(const char* sig_str) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_data_t plain,sig,sig_text; gpgme_verify_result_t result; char* fpr = NULL; char* armored_sig_str = NULL; if (sig_str == NULL) { purple_debug_error(PLUGIN_ID,"verify got null parameter\n"); return NULL; } // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // armor sig_str armored_sig_str = str_armor(sig_str); // create data containers gpgme_data_new_from_mem (&sig, armored_sig_str,strlen(armored_sig_str),1); gpgme_data_new(&plain); // try to verify error = gpgme_op_verify(ctx,sig,NULL,plain); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_verify failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // get result result = gpgme_op_verify_result (ctx); if (result != NULL) { if (result->signatures != NULL) { // return the fingerprint of the key that made the signature fpr = g_strdup(result->signatures->fpr); } } // release memory for data containers gpgme_data_release(sig); gpgme_data_release(plain); return fpr; }
GSList * get_available_keys () { init_gpgme (); gpgme_ctx_t ctx; gpgme_key_t key; gpgme_error_t err = gpgme_new (&ctx); if (err) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (err), gpgme_strerror (err)); return GPGME_ERROR; } err = gpgme_op_keylist_start (ctx, NULL, 1); if (err) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (err), gpgme_strerror (err)); gpgme_release (ctx); return GPGME_ERROR; } GSList *list = NULL; KeyInfo *key_info; while (1) { err = gpgme_op_keylist_next (ctx, &key); if (err) { break; } key_info = g_new0 (KeyInfo, 1); key_info->key_id = g_strdup (key->subkeys->keyid); if (key->uids && key->uids->name) { key_info->name = g_strdup (key->uids->name); } else { key_info->name = g_strdup ("none"); } if (key->uids && key->uids->email) { key_info->email = g_strdup (key->uids->email); } else { key_info->email = g_strdup ("none"); } key_info->key_fpr = g_strdup (key->subkeys->fpr); gssize bytes_to_copy = sizeof (KeyInfo) + g_utf8_strlen (key_info->name, -1) + g_utf8_strlen (key_info->email, -1) + g_utf8_strlen (key_info->key_id, -1) + g_utf8_strlen (key_info->key_fpr, -1) + 4; list = g_slist_append (list, g_memdup (key_info, bytes_to_copy)); g_free (key_info); gpgme_key_release (key); } gpgme_release (ctx); return list; }
void p_gpg_verify(const char *const barejid, const char *const sign) { if (!sign) { return; } gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return; } char *sign_with_header_footer = _add_header_footer(sign, PGP_SIGNATURE_HEADER, PGP_SIGNATURE_FOOTER); gpgme_data_t sign_data; gpgme_data_new_from_mem(&sign_data, sign_with_header_footer, strlen(sign_with_header_footer), 1); free(sign_with_header_footer); gpgme_data_t plain_data; gpgme_data_new(&plain_data); error = gpgme_op_verify(ctx, sign_data, NULL, plain_data); gpgme_data_release(sign_data); gpgme_data_release(plain_data); if (error) { log_error("GPG: Failed to verify. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return; } gpgme_verify_result_t result = gpgme_op_verify_result(ctx); if (result) { if (result->signatures) { gpgme_key_t key = NULL; error = gpgme_get_key(ctx, result->signatures->fpr, &key, 0); if (error) { log_debug("Could not find PGP key with ID %s for %s", result->signatures->fpr, barejid); } else { log_debug("Fingerprint found for %s: %s ", barejid, key->subkeys->fpr); ProfPGPPubKeyId *pubkeyid = malloc(sizeof(ProfPGPPubKeyId)); pubkeyid->id = strdup(key->subkeys->keyid); pubkeyid->received = TRUE; g_hash_table_replace(pubkeys, strdup(barejid), pubkeyid); } gpgme_key_unref(key); } } gpgme_release(ctx); }
/* ------------------ * decrypt a plain string with the key found with fingerprint fpr * FREE MEMORY AFTER USAGE OF RETURN VALUE * ------------------ */ static char* decrypt(char* cipher_str) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_data_t plain,cipher; size_t len = 0; char* plain_str = NULL; char* plain_str_dup = NULL; char* armored_buffer; // add header and footer: armored_buffer = str_armor(cipher_str); // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // create data containers gpgme_data_new_from_mem (&cipher, armored_buffer,strlen(armored_buffer),1); gpgme_data_new(&plain); // decrypt error = gpgme_op_decrypt(ctx,cipher,plain); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_decrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers gpgme_data_release(cipher); plain_str = gpgme_data_release_and_get_mem(plain,&len); if (plain_str != NULL) { plain_str[len] = 0; plain_str_dup = g_strdup(plain_str); } gpgme_free(plain_str); // close gpgme connection gpgme_release (ctx); return plain_str_dup; }
void c_gpgme::remove_key_from_keyring ( const std::string &fingerprint ) { gpgme_key_t key; m_error_code = gpgme_get_key(m_ctx, fingerprint.c_str(), &key, 0); if (m_error_code != GPG_ERR_NO_ERROR) { throw std::runtime_error(gpgme_strsource(m_error_code)); } m_error_code = gpgme_op_delete(m_ctx, key, 0); if (m_error_code != GPG_ERR_NO_ERROR) { throw std::runtime_error(gpgme_strsource(m_error_code)); } }
/* ------------------ * preferences dialog function * ------------------ */ static PurplePluginPrefFrame * get_plugin_pref_frame(PurplePlugin *plugin) { PurplePluginPrefFrame *frame; PurplePluginPref *ppref; gpgme_error_t error; gpgme_ctx_t ctx; gpgme_key_t key; // create preferences frame frame = purple_plugin_pref_frame_new(); // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // create key chooser preference ppref = purple_plugin_pref_new_with_name_and_label(PREF_MY_KEY,"My key"); purple_plugin_pref_set_type(ppref, PURPLE_PLUGIN_PREF_CHOICE); purple_plugin_pref_add_choice(ppref, "None", ""); // list keys (secret keys) error = gpgme_op_keylist_start (ctx,NULL,1); if (error == GPG_ERR_NO_ERROR) { while (!error) { error = gpgme_op_keylist_next (ctx, &key); if (error) break; // add key to preference chooser //TODO: find something better for g_strdup, or some possibility to free memory after preferences dialog closed purple_plugin_pref_add_choice(ppref, g_strdup(key->uids->uid), g_strdup(key->subkeys->fpr)); purple_debug_info(PLUGIN_ID,"Found secret key for: %s has fpr %s\n",key->uids->uid,key->subkeys->fpr); gpgme_key_release (key); } }else { purple_debug_error(PLUGIN_ID,"gpgme_op_keylist_start failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); } // close gpgme connection gpgme_release (ctx); purple_plugin_pref_frame_add(frame, ppref); return frame; }
static int gpgme_error_to_errno (gpgme_error_t err) { int res = gpg_err_code_to_errno (err); if (!err) { switch (gpg_err_code (err)) { case GPG_ERR_EOF: res = 0; break; case GPG_ERR_INV_VALUE: res = EINVAL; break; case GPG_ERR_NOT_SUPPORTED: res = ENOSYS; break; default: /* FIXME: Yeah, well. */ res = EINVAL; break; } } TRACE3 (DEBUG_DATA, "gpgme:gpgme_error_to_errno", 0, "mapping %s <%s> to: %s", gpgme_strerror (err), gpgme_strsource (err), strerror (res)); errno = res; return res ? -1 : 0; }
gpgme_error_t geanypg_show_err_msg(gpgme_error_t err) { gchar const * msg = (gchar const *)gpgme_strerror(err); gchar const * src = (gchar const *)gpgme_strsource(err); dialogs_show_msgbox(GTK_MESSAGE_ERROR, "%s %s: %s\n", _("Error from"), src, msg); fprintf(stderr, "GeanyPG: %s %s: %s\n", _("Error from"), msg, src); return err; }
bool KGpgMe::encrypt(const QByteArray& inBuffer, Q_ULONG length, QByteArray* outBuffer, QString keyid /* = QString::null */) { gpgme_error_t err = 0; gpgme_data_t in = 0, out = 0; gpgme_key_t keys[2] = { NULL, NULL }; gpgme_key_t* key = NULL; gpgme_encrypt_result_t result = 0; outBuffer->resize(0); if(m_ctx) { err = gpgme_data_new_from_mem(&in, inBuffer.data(), length, 1); if(!err) { err = gpgme_data_new(&out); if(!err) { if(keyid.isNull()) { key = NULL; } else { err = gpgme_get_key(m_ctx, keyid.ascii(), &keys[0], 0); key = keys; } if(!err) { err = gpgme_op_encrypt(m_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, in, out); if(!err) { result = gpgme_op_encrypt_result(m_ctx); if (result->invalid_recipients) { KMessageBox::error(kapp->activeWindow(), QString("%1: %2") .arg(i18n("That public key is not meant for encryption")) .arg(result->invalid_recipients->fpr)); } else { err = readToBuffer(out, outBuffer); } } } } } } if(err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) { KMessageBox::error(kapp->activeWindow(), QString("%1: %2") .arg(gpgme_strsource(err)).arg(gpgme_strerror(err))); } if(err != GPG_ERR_NO_ERROR) clearCache(); if(keys[0]) gpgme_key_unref(keys[0]); if(in) gpgme_data_release(in); if(out) gpgme_data_release(out); return (err == GPG_ERR_NO_ERROR); }
/* ------------------ * import ascii armored key * ------------------ */ int import_key(char* armored_key) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_data_t keydata; gpgme_import_result_t result; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return FALSE; } purple_debug_info(PLUGIN_ID,"try to import key: %s\n",armored_key); // create data containers gpgme_data_new_from_mem (&keydata, armored_key,strlen(armored_key),1); // import key, ascii armored gpgme_set_armor(ctx,1); error = gpgme_op_import (ctx, keydata); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_import: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return FALSE; } result = gpgme_op_import_result (ctx); purple_debug_info(PLUGIN_ID,"considered keys: %d; imported keys: %d; not imported keys: %d\n",result->considered,result->imported,result->not_imported); // release memory for data containers gpgme_data_release(keydata); // close gpgme connection gpgme_release (ctx); return TRUE; }
//------------------------------------------------------------------------------ string dump_gpgme_error_t(gpgme_error_t err) { string buf; size_t n = 1024; buf.resize(n); const int res = gpgme_strerror_r(err, buf.data(), n); if(res != 0) return "Failed to fetch error description"; else buf.resize(strlen(buf.c_str())); return fmt::to_string(buf, " [", gpgme_strsource(err), ']'); }
void KGpgMe::init(gpgme_protocol_t proto) { gpgme_error_t err; gpgme_check_version(NULL); setlocale(LC_ALL, ""); gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); err = gpgme_engine_check_version(proto); if(err) { KMessageBox::error(kapp->activeWindow(), QString("%1: %2") .arg(gpgme_strsource(err)).arg(gpgme_strerror(err))); } }
/* XXXX. This is the synchronous variant. */ gpgme_error_t gpgme_op_assuan_transact_ext (gpgme_ctx_t ctx, const char *command, gpgme_assuan_data_cb_t data_cb, void *data_cb_value, gpgme_assuan_inquire_cb_t inq_cb, void *inq_cb_value, gpgme_assuan_status_cb_t status_cb, void *status_cb_value, gpgme_error_t *op_err_p) { gpgme_error_t err; gpgme_error_t op_err; TRACE_BEG8 (DEBUG_CTX, "gpgme_op_assuan_transact", ctx, "command=%s, data_cb=%p/%p, inq_cb=%p/%p, status_cb=%p/%p, " "op_err=%p", command, data_cb, data_cb_value, inq_cb, inq_cb_value, status_cb, status_cb_value, op_err_p); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); err = opassuan_start (ctx, 1, command, data_cb, data_cb_value, inq_cb, inq_cb_value, status_cb, status_cb_value); if (err) goto out; err = _gpgme_wait_one_ext (ctx, &op_err); if (op_err) { TRACE_LOG2 ("op_err = %s <%s>", gpgme_strerror (op_err), gpgme_strsource (op_err)); if (! op_err_p) { TRACE_LOG ("warning: operational error ignored by user"); } } if (op_err_p) *op_err_p = op_err; out: return TRACE_ERR (err); }
KGpgKeyList KGpgMe::keys(bool privateKeys /* = false */) const { KGpgKeyList keys; gpgme_error_t err = 0, err2 = 0; gpgme_key_t key = 0; gpgme_keylist_result_t result = 0; if(m_ctx) { err = gpgme_op_keylist_start(m_ctx, NULL, privateKeys); if(!err) { while(!(err = gpgme_op_keylist_next(m_ctx, &key))) { KGpgKey gpgkey; if(!key->subkeys) continue; gpgkey.id = key->subkeys->keyid; if(key->uids) { gpgkey.name = key->uids->name; gpgkey.email = key->uids->email; } keys.append(gpgkey); gpgme_key_unref(key); } if (gpg_err_code (err) == GPG_ERR_EOF) err = 0; err2 = gpgme_op_keylist_end(m_ctx); if(!err) err = err2; } } if(err) { KMessageBox::error(kapp->activeWindow(), QString("%1: %2") .arg(gpgme_strsource(err)).arg(gpgme_strerror(err))); } else { result = gpgme_op_keylist_result(m_ctx); if (result->truncated) { KMessageBox::error(kapp->activeWindow(), i18n("Key listing unexpectedly truncated.")); } } return keys; }
/* * set a GError form GpgME information */ static void g_set_error_from_gpgme(GError ** error, gpgme_error_t gpgme_err, const gchar * message) { gchar *errstr; gchar *srcstr; if (!error) return; srcstr = g_strdup(gpgme_strsource(gpgme_err)); UTF8_VALID_STR(srcstr); errstr = g_strdup(gpgme_strerror(gpgme_err)); UTF8_VALID_STR(errstr); g_set_error(error, GPGME_ERROR_QUARK, gpgme_err, "%s: %s: %s", srcstr, message, errstr); g_free(srcstr); g_free(errstr); }
bool KGpgMe::decrypt(const QByteArray& inBuffer, QByteArray* outBuffer) { gpgme_error_t err = 0; gpgme_data_t in = 0, out = 0; gpgme_decrypt_result_t result = 0; outBuffer->resize(0); if(m_ctx) { err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1); if(!err) { err = gpgme_data_new(&out); if(!err) { err = gpgme_op_decrypt(m_ctx, in, out); if(!err) { result = gpgme_op_decrypt_result(m_ctx); if(result->unsupported_algorithm) { KMessageBox::error(kapp->activeWindow(), QString("%1: %2") .arg(i18n("Unsupported algorithm")) .arg(result->unsupported_algorithm)); } else { err = readToBuffer(out, outBuffer); } } } } } if(err != GPG_ERR_NO_ERROR && err != GPG_ERR_CANCELED) { KMessageBox::error(kapp->activeWindow(), QString("%1: %2") .arg(gpgme_strsource(err)).arg(gpgme_strerror(err))); } if(err != GPG_ERR_NO_ERROR) clearCache(); if(in) gpgme_data_release(in); if(out) gpgme_data_release(out); return (err == GPG_ERR_NO_ERROR); }
GHashTable* p_gpg_list_keys(void) { gpgme_error_t error; GHashTable *result = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_p_gpg_free_key); gpgme_ctx_t ctx; error = gpgme_new(&ctx); if (error) { log_error("GPG: Could not list keys. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } error = gpgme_op_keylist_start(ctx, NULL, 0); if (error == GPG_ERR_NO_ERROR) { gpgme_key_t key; error = gpgme_op_keylist_next(ctx, &key); while (!error) { gpgme_subkey_t sub = key->subkeys; ProfPGPKey *p_pgpkey = _p_gpg_key_new(); p_pgpkey->id = strdup(sub->keyid); p_pgpkey->name = strdup(key->uids->uid); p_pgpkey->fp = strdup(sub->fpr); if (sub->can_encrypt) p_pgpkey->encrypt = TRUE; if (sub->can_authenticate) p_pgpkey->authenticate = TRUE; if (sub->can_certify) p_pgpkey->certify = TRUE; if (sub->can_sign) p_pgpkey->sign = TRUE; sub = sub->next; while (sub) { if (sub->can_encrypt) p_pgpkey->encrypt = TRUE; if (sub->can_authenticate) p_pgpkey->authenticate = TRUE; if (sub->can_certify) p_pgpkey->certify = TRUE; if (sub->can_sign) p_pgpkey->sign = TRUE; sub = sub->next; } g_hash_table_insert(result, strdup(p_pgpkey->name), p_pgpkey); gpgme_key_unref(key); error = gpgme_op_keylist_next(ctx, &key); } } error = gpgme_op_keylist_start(ctx, NULL, 1); if (error == GPG_ERR_NO_ERROR) { gpgme_key_t key; error = gpgme_op_keylist_next(ctx, &key); while (!error) { gpgme_subkey_t sub = key->subkeys; while (sub) { if (sub->secret) { ProfPGPKey *p_pgpkey = g_hash_table_lookup(result, key->uids->uid); if (p_pgpkey) { p_pgpkey->secret = TRUE; } } sub = sub->next; } gpgme_key_unref(key); error = gpgme_op_keylist_next(ctx, &key); } } gpgme_release(ctx); autocomplete_clear(key_ac); GList *ids = g_hash_table_get_keys(result); GList *curr = ids; while (curr) { ProfPGPKey *key = g_hash_table_lookup(result, curr->data); autocomplete_add(key_ac, key->id); curr = curr->next; } g_list_free(ids); return result; }
void p_gpg_on_connect(const char *const barejid) { char *pgpdir = files_get_data_path(DIR_PGP); GString *pubsfile = g_string_new(pgpdir); free(pgpdir); gchar *account_dir = str_replace(barejid, "@", "_at_"); g_string_append(pubsfile, "/"); g_string_append(pubsfile, account_dir); free(account_dir); // mkdir if doesn't exist for account errno = 0; int res = g_mkdir_with_parents(pubsfile->str, S_IRWXU); if (res == -1) { char *errmsg = strerror(errno); if (errmsg) { log_error("Error creating directory: %s, %s", pubsfile->str, errmsg); } else { log_error("Error creating directory: %s", pubsfile->str); } } // create or read publickeys g_string_append(pubsfile, "/pubkeys"); pubsloc = pubsfile->str; g_string_free(pubsfile, FALSE); if (g_file_test(pubsloc, G_FILE_TEST_EXISTS)) { g_chmod(pubsloc, S_IRUSR | S_IWUSR); } pubkeyfile = g_key_file_new(); g_key_file_load_from_file(pubkeyfile, pubsloc, G_KEY_FILE_KEEP_COMMENTS, NULL); // load each keyid gsize len = 0; gchar **jids = g_key_file_get_groups(pubkeyfile, &len); gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); g_strfreev(jids); return; } int i = 0; for (i = 0; i < len; i++) { GError *gerr = NULL; gchar *jid = jids[i]; gchar *keyid = g_key_file_get_string(pubkeyfile, jid, "keyid", &gerr); if (gerr) { log_error("Error loading PGP key id for %s", jid); g_error_free(gerr); g_free(keyid); } else { gpgme_key_t key = NULL; error = gpgme_get_key(ctx, keyid, &key, 0); if (error || key == NULL) { log_warning("GPG: Failed to get key for %s: %s %s", jid, gpgme_strsource(error), gpgme_strerror(error)); continue; } ProfPGPPubKeyId *pubkeyid = malloc(sizeof(ProfPGPPubKeyId)); pubkeyid->id = strdup(keyid); pubkeyid->received = FALSE; g_hash_table_replace(pubkeys, strdup(jid), pubkeyid); g_free(keyid); gpgme_key_unref(key); } } gpgme_release(ctx); g_strfreev(jids); _save_pubkeys(); }
char* p_gpg_encrypt(const char *const barejid, const char *const message, const char *const fp) { ProfPGPPubKeyId *pubkeyid = g_hash_table_lookup(pubkeys, barejid); if (!pubkeyid) { return NULL; } if (!pubkeyid->id) { return NULL; } gpgme_key_t keys[3]; keys[0] = NULL; keys[1] = NULL; keys[2] = NULL; gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_key_t receiver_key; error = gpgme_get_key(ctx, pubkeyid->id, &receiver_key, 0); if (error || receiver_key == NULL) { log_error("GPG: Failed to get receiver_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } keys[0] = receiver_key; gpgme_key_t sender_key = NULL; error = gpgme_get_key(ctx, fp, &sender_key, 0); if (error || sender_key == NULL) { log_error("GPG: Failed to get sender_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } keys[1] = sender_key; gpgme_data_t plain; gpgme_data_new_from_mem(&plain, message, strlen(message), 1); gpgme_data_t cipher; gpgme_data_new(&cipher); gpgme_set_armor(ctx, 1); error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); gpgme_data_release(plain); gpgme_release(ctx); gpgme_key_unref(receiver_key); gpgme_key_unref(sender_key); if (error) { log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } size_t len; char *cipher_str = gpgme_data_release_and_get_mem(cipher, &len); char *result = NULL; if (cipher_str) { GString *cipher_gstr = g_string_new(""); g_string_append_len(cipher_gstr, cipher_str, len); result = _remove_header_footer(cipher_gstr->str, PGP_MESSAGE_FOOTER); g_string_free(cipher_gstr, TRUE); gpgme_free(cipher_str); } return result; }
char* p_gpg_sign(const char *const str, const char *const fp) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL); gpgme_key_t key = NULL; error = gpgme_get_key(ctx, fp, &key, 1); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } gpgme_signers_clear(ctx); error = gpgme_signers_add(ctx, key); gpgme_key_unref(key); if (error) { log_error("GPG: Failed to load signer. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } char *str_or_empty = NULL; if (str) { str_or_empty = strdup(str); } else { str_or_empty = strdup(""); } gpgme_data_t str_data; gpgme_data_new_from_mem(&str_data, str_or_empty, strlen(str_or_empty), 1); free(str_or_empty); gpgme_data_t signed_data; gpgme_data_new(&signed_data); gpgme_set_armor(ctx,1); error = gpgme_op_sign(ctx, str_data, signed_data, GPGME_SIG_MODE_DETACH); gpgme_data_release(str_data); gpgme_release(ctx); if (error) { log_error("GPG: Failed to sign string. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_data_release(signed_data); return NULL; } char *result = NULL; size_t len = 0; char *signed_str = gpgme_data_release_and_get_mem(signed_data, &len); if (signed_str) { GString *signed_gstr = g_string_new(""); g_string_append_len(signed_gstr, signed_str, len); result = _remove_header_footer(signed_gstr->str, PGP_SIGNATURE_FOOTER); g_string_free(signed_gstr, TRUE); gpgme_free(signed_str); } if (passphrase_attempt) { passphrase = strdup(passphrase_attempt); } return result; }
char* p_gpg_decrypt(const char *const cipher) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL); char *cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER); gpgme_data_t cipher_data; gpgme_data_new_from_mem(&cipher_data, cipher_with_headers, strlen(cipher_with_headers), 1); free(cipher_with_headers); gpgme_data_t plain_data; gpgme_data_new(&plain_data); error = gpgme_op_decrypt(ctx, cipher_data, plain_data); gpgme_data_release(cipher_data); if (error) { log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_data_release(plain_data); gpgme_release(ctx); return NULL; } gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx); if (res) { GString *recipients_str = g_string_new(""); gpgme_recipient_t recipient = res->recipients; while (recipient) { gpgme_key_t key; error = gpgme_get_key(ctx, recipient->keyid, &key, 1); if (!error && key) { const char *addr = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, NULL, 0); if (addr) { g_string_append(recipients_str, addr); } gpgme_key_unref(key); } if (recipient->next) { g_string_append(recipients_str, ", "); } recipient = recipient->next; } log_debug("GPG: Decrypted message for recipients: %s", recipients_str->str); g_string_free(recipients_str, TRUE); } gpgme_release(ctx); size_t len = 0; char *plain_str = gpgme_data_release_and_get_mem(plain_data, &len); char *result = NULL; if (plain_str) { plain_str[len] = 0; result = g_strdup(plain_str); } gpgme_free(plain_str); if (passphrase_attempt) { passphrase = strdup(passphrase_attempt); } return result; }
gpointer sign_file (const gchar *input_file_path, const gchar *fpr) { gpgme_error_t error; gpgme_ctx_t context; gpgme_key_t signing_key; gpgme_data_t clear_text, signed_text; gpgme_sign_result_t result; gchar *buffer; gssize nbytes; error = gpgme_new (&context); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); return GPGME_ERROR; } gpgme_set_armor (context, 0); error = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (context); return GPGME_ERROR; } const char *keyring_dir = gpgme_get_dirinfo ("homedir"); error = gpgme_ctx_set_engine_info (context, GPGME_PROTOCOL_OpenPGP, NULL, keyring_dir); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (context); return GPGME_ERROR; } error = gpgme_get_key (context, fpr, &signing_key, 1); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (context); return GPGME_ERROR; } error = gpgme_signers_add (context, signing_key); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); cleanup (NULL, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } FILE *infp = g_fopen (input_file_path, "r"); if (infp == NULL) { g_printerr ("Couldn't open input file\n"); cleanup (NULL, NULL, NULL, NULL, &signing_key, &context); return FILE_OPEN_ERROR; } error = gpgme_data_new_from_stream (&clear_text, infp); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } error = gpgme_data_new (&signed_text); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } error = gpgme_op_sign (context, clear_text, signed_text, GPGME_SIG_MODE_DETACH); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } result = gpgme_op_sign_result (context); if (result->invalid_signers) { g_printerr ("Invalid signer found: %s\n", result->invalid_signers->fpr); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } if (!result->signatures || result->signatures->next) { g_printerr ("Unexpected number of signatures created\n"); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } error = gpgme_data_seek (signed_text, 0, SEEK_SET); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } buffer = g_try_malloc0 (SIG_MAXLEN); if (buffer == NULL) { g_printerr ("Couldn't allocate memory\n"); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return MEMORY_ALLOCATION_ERROR; } nbytes = gpgme_data_read (signed_text, buffer, SIG_MAXLEN); if (nbytes == -1) { g_printerr ("Error while reading data\n"); cleanup (infp, NULL, NULL, NULL, &signing_key, &context); return GPGME_ERROR; } GError *gerr = NULL; gchar *output_file_path = g_strconcat (input_file_path, ".sig", NULL); GFile *fpout = g_file_new_for_path (output_file_path); GFileOutputStream *ostream = g_file_append_to (fpout, G_FILE_CREATE_REPLACE_DESTINATION, NULL, &gerr); if (gerr != NULL) { g_printerr ("Couldn't open output file for writing\n"); cleanup (infp, fpout, NULL, output_file_path, &signing_key, &context); return FILE_OPEN_ERROR; } gssize wbytes = g_output_stream_write (G_OUTPUT_STREAM (ostream), buffer, nbytes, NULL, &gerr); if (wbytes == -1) { g_printerr ("Couldn't write the request number of bytes (%s)\n", gerr->message); cleanup (infp, fpout, ostream, output_file_path, &signing_key, &context); return FILE_WRITE_ERROR; } cleanup (infp, fpout, ostream, output_file_path, &signing_key, &context); return SIGN_OK; }
gpointer verify_signature (const gchar *detached_signature_path, const gchar *signed_file_path) { init_gpgme (); gpgme_ctx_t ctx; gpgme_signature_t sig; gpgme_data_t signature_data, signed_data; gpgme_error_t error = gpgme_new (&ctx); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); return GPGME_ERROR; } gpgme_set_armor (ctx, 1); error = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return GPGME_ERROR; } const char *keyring_dir = gpgme_get_dirinfo ("homedir"); error = gpgme_ctx_set_engine_info (ctx, GPGME_PROTOCOL_OpenPGP, NULL, keyring_dir); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return GPGME_ERROR; } FILE *sig_fp = g_fopen (detached_signature_path, "r"); FILE *sig_data_fp = g_fopen (signed_file_path, "r"); if (sig_fp == NULL || sig_data_fp == NULL) { g_printerr ("Couldn't open input file\n"); gpgme_release (ctx); return FILE_OPEN_ERROR; } error = gpgme_data_new_from_stream (&signature_data, sig_fp); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); fclose (sig_fp); fclose (sig_data_fp); gpgme_release (ctx); return GPGME_ERROR; } error = gpgme_data_new_from_stream (&signed_data, sig_data_fp); if (error) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); fclose (sig_fp); fclose (sig_data_fp); gpgme_release (ctx); gpgme_data_release (signature_data); return GPGME_ERROR; } error = gpgme_op_verify (ctx, signature_data, signed_data, NULL); gpgme_data_release (signature_data); gpgme_data_release (signed_data); fclose (sig_fp); fclose (sig_data_fp); if (error != GPG_ERR_NO_ERROR) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return GPGME_ERROR; } gpgme_verify_result_t result = gpgme_op_verify_result (ctx); if (!result) { g_printerr ("%s:%d: %s: %s\n", __FILE__, __LINE__, gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return GPGME_ERROR; } sig = result->signatures; if (!sig) { gpgme_release (ctx); return NO_GPG_KEYS_AVAILABLE; } for (; sig; sig = sig->next) { if ((sig->summary & GPGME_SIGSUM_VALID) || (sig->summary & GPGME_SIGSUM_GREEN)) { gpgme_release (ctx); return SIGNATURE_OK; } else if (sig->summary == 0 && sig->status == GPG_ERR_NO_ERROR) { // Valid but key is not certified with a trusted signature gpgme_release (ctx); return SIGNATURE_OK_KEY_NOT_TRUSTED; } } gpgme_release (ctx); return BAD_SIGNATURE; }
/* ------------------ * sign a plain string with the key found with fingerprint fpr * FREE MEMORY AFTER USAGE OF RETURN VALUE! * ------------------ */ static char* sign(const char* plain_str,const char* fpr) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_key_t key; gpgme_data_t plain,sig; const int MAX_LEN = 10000; char *sig_str = NULL; char *sig_str_dup = NULL; size_t len = 0; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,1); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // select signers gpgme_signers_clear(ctx); error = gpgme_signers_add (ctx,key); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_signers_add failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // create data containers gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1); gpgme_data_new(&sig); // sign message, ascii armored gpgme_set_armor(ctx,1); error = gpgme_op_sign(ctx,plain,sig,GPGME_SIG_MODE_DETACH); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_sign failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers gpgme_data_release(plain); sig_str = gpgme_data_release_and_get_mem(sig,&len); if (sig_str != NULL) { sig_str[len] = 0; sig_str_dup = str_unarmor(sig_str); } gpgme_free(sig_str); // close gpgme connection gpgme_release (ctx); return sig_str_dup; }
/* ------------------ * encrypt a plain string with the key found with fingerprint fpr * ------------------ */ static char* encrypt(const char* plain_str, const char* fpr) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_key_t key; gpgme_data_t plain,cipher; char* cipher_str = NULL; char* cipher_str_dup = NULL; size_t len; gpgme_key_t key_arr[2]; key_arr[0] = NULL; key_arr[1] = NULL; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,0); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } key_arr[0] = key; // create data containers gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1); gpgme_data_new(&cipher); // encrypt, ascii armored gpgme_set_armor(ctx,1); error = gpgme_op_encrypt (ctx, key_arr,GPGME_ENCRYPT_ALWAYS_TRUST,plain,cipher); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_encrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers gpgme_data_release(plain); cipher_str = gpgme_data_release_and_get_mem(cipher,&len); if (cipher_str != NULL) { cipher_str_dup = str_unarmor(cipher_str); } gpgme_free(cipher_str); // close gpgme connection gpgme_release (ctx); return cipher_str_dup; }