void GPGME::encryptBytesToFile(const QByteArray & data, const QString & filename, const QString & keyId) { setError(GPG_ERR_NO_ERROR); // clear error qDebug() << "Encrypt data to file" << filename; gpgme_error_t err; // check data size if (data.size() > FILESIZE_HARD_LIMIT) { setError(GPGME_WRAPPER_ERR_DATA_TOO_LARGE, true); return; } // list all available keys and find the appropriate err = gpgme_op_keylist_start(p->context, keyId.toLatin1().data(), 0); gpgme_key_t key = 0; gpgme_key_t loop_key = 0; int foundCount = 0; while (1) { err = gpgme_op_keylist_next(p->context, &loop_key); if (err != GPG_ERR_NO_ERROR) { break; } qDebug() << "KEY FOUND"; if (loop_key != 0) { key = loop_key; } foundCount++; } gpgme_op_keylist_end(p->context); if (foundCount > 1) { setError(GPGME_WRAPPER_ERR_MORE_THAN_ONE_KEY_FOUND); return; } if (key == 0) { // key not found setError(GPGME_WRAPPER_ERR_CANNOT_FIND_KEY, true); return; } // if filename ends with ".asc" then use armored output, otherwise use binary if (filename.toLower().endsWith(".asc")) { // use armored output gpgme_set_armor(p->context, 1); qDebug() << "Encode: use armored output"; } gpgme_data_t cipher; gpgme_data_t plain; gpgme_data_new_from_mem(&plain, data.data(), data.size(), 0); // do not copy data // backup file contents QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { setError(GPGME_WRAPPER_ERR_CANNOT_OPEN_FILE, true); return; } if (file.size() > FILESIZE_HARD_LIMIT) { setError(GPGME_WRAPPER_ERR_FILE_TOO_LARGE, true); return; } QByteArray cipherBackup = file.readAll(); file.close(); // prepare file for writing if (!file.open(QIODevice::WriteOnly)) { setError(GPGME_WRAPPER_ERR_CANNOT_OPEN_FILE, true); return; } err = gpgme_data_new_from_fd(&cipher, file.handle()); if (err != GPG_ERR_NO_ERROR) { setError(err); return; } gpgme_key_t keys[2]; keys[0] = key; keys[1] = 0; err = gpgme_op_encrypt(p->context, keys, static_cast<gpgme_encrypt_flags_t>(GPGME_ENCRYPT_ALWAYS_TRUST), plain, cipher); if (err != GPG_ERR_NO_ERROR) { // revert file contents in case of error file.resize(0); file.write(cipherBackup); setError(err); } file.close(); }
/* The main GPG encryption routine for libfko. */ int gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const char *pw, unsigned char **out, size_t *out_len) { char *tmp_buf; int res; gpgme_ctx_t gpg_ctx = NULL; gpgme_data_t cipher = NULL; gpgme_data_t plaintext = NULL; gpgme_key_t key[2] = { NULL, NULL }; gpgme_error_t err; /* Initialize gpgme */ res = init_gpgme(fko_ctx); if(res != FKO_SUCCESS) return(res); gpg_ctx = fko_ctx->gpg_ctx; /* Initialize the plaintext data (place into gpgme_data object) */ err = gpgme_data_new_from_mem(&plaintext, (char*)indata, in_len, 1); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ); } /* Set protocol */ err = gpgme_set_protocol(gpg_ctx, GPGME_PROTOCOL_OpenPGP); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_SET_PROTOCOL); } /* Set ascii-armor off (we will be base64-encoding the encrypted data * ourselves. */ gpgme_set_armor(gpg_ctx, 0); /* The gpgme_encrypt.... functions take a recipient key array, so we add * our single key here. */ key[0] = fko_ctx->recipient_key; /* Create the buffer for our encrypted data. */ err = gpgme_data_new(&cipher); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ); } /* Here we add the signer to the gpgme context if there is one. */ if(fko_ctx->gpg_signer != NULL) { gpgme_signers_clear(gpg_ctx); err = gpgme_signers_add(gpg_ctx, fko_ctx->signer_key); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_data_release(cipher); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_ADD_SIGNER); } } /* Set the passphrase callback. */ gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw); /* Encrypt and sign (if a sig was provided) the SPA data. */ if(fko_ctx->gpg_signer == NULL) err = gpgme_op_encrypt( gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher ); else err = gpgme_op_encrypt_sign( gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher ); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_data_release(cipher); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; if(gpgme_err_code(err) == GPG_ERR_CANCELED) return(FKO_ERROR_GPGME_BAD_PASSPHRASE); return(FKO_ERROR_GPGME_ENCRYPT_SIGN); } /* Done with the plaintext. */ gpgme_data_release(plaintext); /* Get the encrypted data and its length from the gpgme data object. * BTW, this does free the memory used by cipher. */ tmp_buf = gpgme_data_release_and_get_mem(cipher, out_len); *out = malloc(*out_len); /* This is freed upon fko_ctx destruction. */ if(*out == NULL) res = FKO_ERROR_MEMORY_ALLOCATION; else { memcpy(*out, tmp_buf, *out_len); res = FKO_SUCCESS; } gpgme_free(tmp_buf); return(res); }
static gint pgpinline_check_signature(MimeInfo *mimeinfo) { PrivacyDataPGP *data = NULL; gchar *textdata = NULL, *tmp = NULL; gpgme_data_t plain = NULL, cipher = NULL; gpgme_error_t err; cm_return_val_if_fail(mimeinfo != NULL, 0); if (procmime_mimeinfo_parent(mimeinfo) == NULL) { privacy_set_error(_("Incorrect part")); return 0; /* not parent */ } if (mimeinfo->type != MIMETYPE_TEXT) { privacy_set_error(_("Not a text part")); debug_print("type %d\n", mimeinfo->type); return 0; } cm_return_val_if_fail(mimeinfo->privacy != NULL, 0); data = (PrivacyDataPGP *) mimeinfo->privacy; textdata = get_part_as_string(mimeinfo); if (!textdata) { g_free(textdata); privacy_set_error(_("Couldn't get text data.")); return 0; } /* gtk2: convert back from utf8 */ tmp = conv_codeset_strdup(textdata, CS_UTF_8, procmime_mimeinfo_get_parameter(mimeinfo, "charset")); if (!tmp) { tmp = conv_codeset_strdup(textdata, CS_UTF_8, conv_get_locale_charset_str_no_utf8()); } if (!tmp) { g_warning("Can't convert charset to anything sane"); tmp = conv_codeset_strdup(textdata, CS_UTF_8, CS_US_ASCII); } g_free(textdata); if (!tmp) { privacy_set_error(_("Couldn't convert text data to any sane charset.")); return 0; } textdata = g_strdup(tmp); g_free(tmp); if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); g_free(textdata); return 0; } gpgme_set_textmode(data->ctx, 1); gpgme_set_armor(data->ctx, 1); gpgme_data_new_from_mem(&plain, textdata, (size_t)strlen(textdata), 1); gpgme_data_new(&cipher); data->sigstatus = sgpgme_verify_signature(data->ctx, plain, NULL, cipher); gpgme_data_release(plain); gpgme_data_release(cipher); g_free(textdata); return 0; }
/** * crypto: the crypto service (#SeahorseServiceCrypto) * recipients: A list of recipients (keyids "openpgp:B8098FB063E2C811") * Must be empty when symmetric encryption is used. * signer: optional, the keyid of the signer * flags: FLAG_SYMMETRIC to perform symmetric encryption * cleartext: the text to encrypt * clearlength: Length of the cleartext * crypttext: the encrypted text (out) * cryptlength: the length of this text (out) * textmode: TRUE if gpgme should use textmode * ascii_armor: TRUE if GPGME should use ascii armor * error: The Error * * Handles encryption in a generic way. Can be used by several DBus APIs * * Returns TRUE on success **/ static gboolean crypto_encrypt_generic (SeahorseServiceCrypto *crypto, const char **recipients, const char *signer, int flags, const char *cleartext, gsize clearlength, char **crypttext, gsize *cryptlength, gboolean textmode, gboolean ascii_armor, GError **error) { GList *recipkeys = NULL; SeahorseGpgmeOperation *pop; SeahorseObject *signkey = NULL; SeahorseObject *skey; gpgme_key_t *recips; gboolean symmetric = FALSE; gpgme_data_t plain, cipher; gpgme_error_t gerr; gboolean ret = TRUE; GSettings *settings; gchar *keyid; if ((flags & FLAG_SYMMETRIC) == FLAG_SYMMETRIC) symmetric = TRUE; if (symmetric && recipients[0] != NULL) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Recipients specified for symmetric encryption")); return FALSE; } /* The signer */ if (signer && signer[0]) { signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer); if (!signkey) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized signer: %s"), signer); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (signkey) || !(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not valid for signing: %s"), signer); return FALSE; } } if (!symmetric) { /* The recipients */ for( ; recipients[0]; recipients++) { skey = seahorse_context_object_from_dbus (SCTX_APP (), recipients[0]); if (!skey) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized recipient: %s"), recipients[0]); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (skey) || !(seahorse_object_get_flags (skey) & SEAHORSE_FLAG_CAN_ENCRYPT)) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not a valid recipient for encryption: %s"), recipients[0]); return FALSE; } recipkeys = g_list_prepend (recipkeys, SEAHORSE_PGP_KEY (skey)); } if (!recipkeys) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("No recipients specified")); return FALSE; } } pop = seahorse_gpgme_operation_new (NULL); /* new data form text */ gerr = gpgme_data_new_from_mem (&plain, cleartext, clearlength, FALSE); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); gerr = gpgme_data_new (&cipher); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); /* encrypt with armor */ gpgme_set_textmode (pop->gctx, textmode); gpgme_set_armor (pop->gctx, ascii_armor); if (symmetric) { /* gpgme_op_encrypt{_sign,}_start() will perform symmetric encryption * when no recipients are specified. */ recips = NULL; } else { /* Add the default key if set and necessary */ settings = g_settings_new ("org.gnome.crypto.pgp"); if (g_settings_get_boolean (settings, "encrypt-to-self")) { keyid = g_settings_get_string (settings, "default-key"); if (keyid && keyid[0]) { skey = seahorse_context_find_object (NULL, g_quark_from_string (keyid), SEAHORSE_LOCATION_LOCAL); if (SEAHORSE_IS_PGP_KEY (skey)) recipkeys = g_list_append (recipkeys, skey); } g_free (keyid); } g_object_unref (settings); /* Make keys into the right format for GPGME */ recips = keylist_to_keys (recipkeys); g_list_free (recipkeys); } /* Do the encryption */ if (signkey) { gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey))); gerr = gpgme_op_encrypt_sign_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } else { gerr = gpgme_op_encrypt_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } free_keys (recips); /* Frees cipher */ ret = process_crypto_result (pop, gerr, cipher, crypttext, cryptlength, error); g_object_unref (pop); gpgme_data_release (plain); return ret; }
GpgME::Data::Data( const char * buffer, size_t size, bool copy ) { gpgme_data_t data; const gpgme_error_t e = gpgme_data_new_from_mem( &data, buffer, size, int( copy ) ); d = new Private( e ? 0 : data ); d->ref(); }
/* ------------------ * 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; }
static gpg_error_t gpa_file_sign_operation_start (GpaFileSignOperation *op, gpa_file_item_t file_item) { gpg_error_t err; if (file_item->direct_in) { /* No copy is made. */ err = gpgme_data_new_from_mem (&op->plain, file_item->direct_in, file_item->direct_in_len, 0); if (err) { gpa_gpgme_warning (err); return err; } err = gpgme_data_new (&op->sig); if (err) { gpa_gpgme_warning (err); gpgme_data_release (op->plain); op->plain = NULL; return err; } } else { gchar *plain_filename = file_item->filename_in; char *filename_used; file_item->filename_out = destination_filename (plain_filename, gpgme_get_armor (GPA_OPERATION (op)->context->ctx), gpgme_get_protocol (GPA_OPERATION (op)->context->ctx), op->sign_type); /* Open the files */ op->plain_fd = gpa_open_input (plain_filename, &op->plain, GPA_OPERATION (op)->window); if (op->plain_fd == -1) /* FIXME: Error value. */ return gpg_error (GPG_ERR_GENERAL); op->sig_fd = gpa_open_output (file_item->filename_out, &op->sig, GPA_OPERATION (op)->window, &filename_used); if (op->sig_fd == -1) { gpgme_data_release (op->plain); close (op->plain_fd); xfree (filename_used); /* FIXME: Error value. */ return gpg_error (GPG_ERR_GENERAL); } xfree (file_item->filename_out); file_item->filename_out = filename_used; } /* Start the operation */ err = gpgme_op_sign_start (GPA_OPERATION (op)->context->ctx, op->plain, op->sig, op->sign_type); if (err) { gpa_gpgme_warning (err); return err; } /* Show and update the progress dialog */ gtk_widget_show_all (GPA_FILE_OPERATION (op)->progress_dialog); gpa_progress_dialog_set_label (GPA_PROGRESS_DIALOG (GPA_FILE_OPERATION (op)->progress_dialog), file_item->direct_name ? file_item->direct_name : file_item->filename_in); return 0; }
char *CGPGHelper::Encrypt(const char *szPlain, const char *szId, unsigned long nPPID) { #ifdef HAVE_LIBGPGME if (!mCtx) return 0; if (!szPlain) return 0; char szUser[MAX_LINE_LEN], buf[MAX_LINE_LEN]; buf[0] = '\0'; sprintf(szUser, "%s.%lu", szId, nPPID); mKeysIni.SetSection("keys"); ICQUser *u = gUserManager.FetchUser( szId, nPPID, LOCK_R ); if ( u ) { const char *tmp = u->GPGKey(); if ( tmp && tmp[0]!='\0' ) strncpy( buf, tmp, MAX_LINE_LEN-1 ); gUserManager.DropUser( u ); } if ( !buf[0] && !mKeysIni.ReadStr(szUser, buf) ) return 0; gLog.Info("[GPG] Encrypting message to %s.\n", szId); CGPGMEMutex mutex; if (!mutex.Lock()) return 0; gpgme_key_t rcps[2]; gpgme_data_t plain = 0, cipher = 0; gpgme_error_t err; char *szCipher = 0; size_t nRead = 0; rcps[1] = 0; // Still use the old method, gpgme_get_key requires the fingerprint, which // actually isn't very helpful. if (gpgme_op_keylist_start (mCtx, buf, 0) != GPG_ERR_NO_ERROR) gLog.Error("%s[GPG] Couldn't use gpgme recipient: %s\n", L_ERRORxSTR, buf); else { if (gpgme_op_keylist_next(mCtx, rcps) != GPG_ERR_NO_ERROR) gLog.Error("%s[GPG] Couldn't get key: %s\n", L_ERRORxSTR, buf); else { if (gpgme_data_new_from_mem(&plain, szPlain, strlen(szPlain), 0) == GPG_ERR_NO_ERROR && gpgme_data_new(&cipher) == GPG_ERR_NO_ERROR) { if ((err = gpgme_op_encrypt(mCtx, rcps, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher)) == GPG_ERR_NO_ERROR) { szCipher = gpgme_data_release_and_get_mem(cipher, &nRead); cipher = 0; szCipher = (char *)realloc(szCipher, nRead + 1); szCipher[nRead] = 0; } else gLog.Error("%s[GPG] Encryption failed: %s\n", L_ERRORxSTR, gpgme_strerror(err)); } } if (cipher) gpgme_data_release(cipher); if (plain) gpgme_data_release(plain); } gpgme_key_unref(rcps[0]); return szCipher; #else return 0; #endif }
static gint pgpmime_check_signature(MimeInfo *mimeinfo) { PrivacyDataPGP *data; MimeInfo *parent, *signature; FILE *fp; gchar *boundary; gchar *textstr; gpgme_data_t sigdata = NULL, textdata = NULL; gpgme_error_t err; cm_return_val_if_fail(mimeinfo != NULL, -1); cm_return_val_if_fail(mimeinfo->privacy != NULL, -1); data = (PrivacyDataPGP *) mimeinfo->privacy; if ((err = gpgme_new(&data->ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); return 0; } debug_print("Checking PGP/MIME signature\n"); err = gpgme_set_protocol(data->ctx, GPGME_PROTOCOL_OpenPGP); if (err) { debug_print ("gpgme_set_protocol failed: %s\n", gpgme_strerror (err)); } parent = procmime_mimeinfo_parent(mimeinfo); fp = claws_fopen(parent->data.filename, "rb"); cm_return_val_if_fail(fp != NULL, SIGNATURE_INVALID); boundary = g_hash_table_lookup(parent->typeparameters, "boundary"); if (!boundary) { privacy_set_error(_("Signature boundary not found.")); claws_fclose(fp); return 0; } textstr = get_canonical_content(fp, boundary); err = gpgme_data_new_from_mem(&textdata, textstr, (size_t)strlen(textstr), 0); if (err) { debug_print ("gpgme_data_new_from_mem failed: %s\n", gpgme_strerror (err)); } signature = (MimeInfo *) mimeinfo->node->next->data; sigdata = sgpgme_data_from_mimeinfo(signature); err = 0; if (signature->encoding_type == ENC_BASE64) { err = gpgme_data_set_encoding (sigdata, GPGME_DATA_ENCODING_BASE64); } if (err) { debug_print ("gpgme_data_set_encoding failed: %s\n", gpgme_strerror (err)); } data->sigstatus = sgpgme_verify_signature (data->ctx, sigdata, textdata, NULL); gpgme_data_release(sigdata); gpgme_data_release(textdata); g_free(textstr); claws_fclose(fp); return 0; }
static gpg_error_t gpa_file_decrypt_operation_start (GpaFileDecryptOperation *op, gpa_file_item_t file_item) { gpg_error_t err; if (file_item->direct_in) { /* No copy is made. */ err = gpgme_data_new_from_mem (&op->cipher, file_item->direct_in, file_item->direct_in_len, 0); if (err) { gpa_gpgme_warning (err); return err; } err = gpgme_data_new (&op->plain); if (err) { gpa_gpgme_warning (err); gpgme_data_release (op->cipher); op->plain = NULL; return err; } gpgme_set_protocol (GPA_OPERATION (op)->context->ctx, is_cms_data (file_item->direct_in, file_item->direct_in_len) ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP); } else { gchar *cipher_filename = file_item->filename_in; char *filename_used; file_item->filename_out = destination_filename (cipher_filename); /* Open the files */ op->cipher_fd = gpa_open_input (cipher_filename, &op->cipher, GPA_OPERATION (op)->window); if (op->cipher_fd == -1) /* FIXME: Error value. */ return gpg_error (GPG_ERR_GENERAL); op->plain_fd = gpa_open_output (file_item->filename_out, &op->plain, GPA_OPERATION (op)->window, &filename_used); if (op->plain_fd == -1) { gpgme_data_release (op->cipher); close (op->cipher_fd); xfree (filename_used); /* FIXME: Error value. */ return gpg_error (GPG_ERR_GENERAL); } xfree (file_item->filename_out); file_item->filename_out = filename_used; gpgme_set_protocol (GPA_OPERATION (op)->context->ctx, is_cms_file (cipher_filename) ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP); } /* Start the operation. */ err = gpgme_op_decrypt_verify_start (GPA_OPERATION (op)->context->ctx, op->cipher, op->plain); if (err) { gpa_gpgme_warning (err); gpgme_data_release (op->plain); op->plain = NULL; close (op->plain_fd); op->plain_fd = -1; gpgme_data_release (op->cipher); op->cipher = NULL; close (op->cipher_fd); op->cipher_fd = -1; return err; } /* Show and update the progress dialog. */ gtk_widget_show_all (GPA_FILE_OPERATION (op)->progress_dialog); gpa_progress_dialog_set_label (GPA_PROGRESS_DIALOG (GPA_FILE_OPERATION (op)->progress_dialog), file_item->direct_name ? file_item->direct_name : file_item->filename_in); return 0; }
int main() { int fd; gpgme_ctx_t g_context; gpgme_engine_info_t enginfo; gpgme_data_t data; gpgme_error_t gerr; gpg_err_code_t gpg_err; gpgme_data_t g_plain; gpgme_data_t g_plain_recv; gpgme_data_t g_encrypt; gpgme_data_t g_encrypt_send; gpgme_key_t g_recipient[MAX_RCP+1]; char *p; char b_encrypt[BIGBUF+1]; char msg[EOF_L_MESSAGE]; char msg_in[EOF_L_MESSAGE]; int i, tmp; for(i=0;i<EOF_L_MESSAGE; i++) msg_in[i] = 0; for(i=0;i<EOF_L_MESSAGE; i++) msg[i] = 0; for(i=0;i<=BIGBUF; i++) b_encrypt[i] = 0; gpgme_check_version(NULL); gerr = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP); if(gerr != GPG_ERR_NO_ERROR) return 10; p = (char *) gpgme_get_protocol_name(GPGME_PROTOCOL_OpenPGP); printf("Version: %s\n",p); gerr = gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, NULL, home); if(gerr == GPG_ERR_NO_ERROR) { printf("gpgme_set_engine_info: ok\n"); } else { printf("gpgme_set_engine_info: err\n"); } /* get engine information */ gerr = gpgme_get_engine_info(&enginfo); if(gerr != GPG_ERR_NO_ERROR) return 3; printf("file=%s, home=%s\n",enginfo->file_name,enginfo->home_dir); /* create our own context */ gerr = gpgme_new(&g_context); if(gerr != GPG_ERR_NO_ERROR) return 1; /* FIXME: both needed? */ /* FIXME: why is the path (FILE_NAME) needed? */ /* FIXME: /usr/bin/gpg must be changed to ~/.ceof/gpg/binary or similar */ gerr = gpgme_ctx_set_engine_info (g_context, GPGME_PROTOCOL_OpenPGP, "/usr/bin/gpg",home); if(gerr != GPG_ERR_NO_ERROR) return 4; /* do not ascii armor data; use 1 for testing */ //gpgme_set_armor(g_context, 0); gpgme_set_armor(g_context, 1); /* create buffers */ gerr = gpgme_data_new(&data); if(gerr != GPG_ERR_NO_ERROR) return 12; gerr = gpgme_data_new(&g_plain_recv); if(gerr != GPG_ERR_NO_ERROR) return 20; gerr = gpgme_data_new(&g_encrypt); if(gerr != GPG_ERR_NO_ERROR) return 14; gerr = gpgme_data_new(&g_encrypt_send); if(gerr != GPG_ERR_NO_ERROR) return 24; /* fill buffers */ /* gerr = gpgme_data_new(&g_plain); if(gerr != GPG_ERR_NO_ERROR) return 13; printf("strlen(%s) = %d\n",msg,i); i -= gpgme_data_write(g_plain, msg, i); if(i) { printf("size mismatch\n"); return 12; } */ strncpy(msg, "==> Erste Nachricht\n\n", EOF_L_MESSAGE); i = strlen(msg); gerr = gpgme_data_new_from_mem (&g_plain, msg, i, 0); /* setup recipient */ gerr = gpgme_op_keylist_start(g_context, "nico schottelius", 0); if(gerr != GPG_ERR_NO_ERROR) return 11; i=0; gerr = gpgme_op_keylist_next(g_context, &g_recipient[0]); while((gpg_err = gpg_err_code(gerr)) != GPG_ERR_EOF) { /* for testing: one call of gpgme_op_keylist_next is enough */ break; if(gerr == GPG_ERR_INV_VALUE) { printf("invalid pointer\n"); return 15; } else if(gerr == GPG_ERR_ENOMEM) { printf("no mem\n"); return 16; } printf ("%s: %s <%s> (%d)\n", g_recipient[0]->subkeys->keyid, g_recipient[0]->uids->name, g_recipient[0]->uids->email, i); i++; /* FIXME: this resets the good filled buffer ... */ gerr = gpgme_op_keylist_next(g_context, &g_recipient[0]); } g_recipient[1] = NULL; /* all above seems to be wrong ... */ gerr = gpgme_get_key(g_context,"775506B45998BF57D0D4AFF27C6E747C38616ADC", &g_recipient[0], 0); if(gerr != GPG_ERR_NO_ERROR) return 32; /* en/decrypt message */ //gerr = gpgme_op_encrypt_sign(g_context, g_recipient, 0, g_plain, g_encrypt); gerr = gpgme_op_encrypt(g_context, g_recipient, 0, g_plain, g_encrypt); if(gerr != GPG_ERR_NO_ERROR) { printf("gerr=%d\n",gerr); return 18; } /* transfer the data into our own buffer, * so the data is saved; you cannot * reuse the gpgme buffers directly as in * gerr = gpgme_op_decrypt(g_context, g_encrypt, g_plain_recv); * */ i = gpgme_data_seek(g_encrypt, 0, SEEK_END); if(i > BIGBUF) return 22; printf("buflen: %d\n",i); /* reset to the beginning */ gpgme_data_seek(g_encrypt, 0, SEEK_SET); if(gpgme_data_read(g_encrypt, b_encrypt, i) == -1) { perror("pgme_data_read"); return 23; } printf("crypt:\n%s\n", b_encrypt); fd = open("testcrypt",O_RDWR|O_CREAT); if(fd == -1) return 40; if(write_all(fd, b_encrypt, BIGBUF) <= 0) return 41; close(fd); /* until here it works, testcrypt contains * data and can be decrypted ... * * perhaps the context needs some reset? */ if((tmp = gpgme_data_write(g_encrypt_send, b_encrypt, i)) == -1) { perror("pgme_data_write"); return 23; } printf("crypt-wrote:%d\n", tmp); /* look for contexts */ gerr = gpgme_op_decrypt(g_context, g_encrypt_send, g_plain_recv); if(gerr != GPG_ERR_NO_ERROR) { printf("gerr=%d\n",gerr); return 19; } /* open communication channel: netcat */ /* listen for input from: * stdin * communication channel */ /* de/encode data from comm channel */ return 1; }
int main(void) { gpgme_check_version (NULL); gpgme_error_t err; gpgme_data_t plain, cipher; gpgme_ctx_t ctx; gpgme_key_t recp[2] = { NULL, NULL }; gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST; char *plaintext = "foo bar\0"; char *fp = "845B80B9AD12DB400CE534F6837EED10F97A36A1"; char *result_file = "./result.gpg"; char *verify_file = "./result"; size_t max_buflen = 2048, buflen; char *buf = malloc(max_buflen * sizeof(char)); FILE *fh = NULL; err = gpgme_new (&ctx); if(err) return bang (err); gpgme_set_armor (ctx, 1); err = gpgme_get_key (ctx, fp, &recp[0], 0); if(err) return bang (err); err = gpgme_data_new_from_mem (&plain, plaintext, strlen(plaintext), 0); if(err) return bang (err); err = gpgme_data_new (&cipher); if(err) return bang (err); err = gpgme_op_encrypt (ctx, recp, flags, plain, cipher); if(err) return bang (err); gpgme_data_seek(cipher, 0, SEEK_SET); buflen = gpgme_data_read(cipher, buf, max_buflen); if (1 > buflen || buflen == max_buflen) return bang_ ("Failed to read ciphertext"); fh = fopen(result_file, "w"); if(!fh) bang_ ("failed to open result_file"); fwrite(buf, sizeof(char), buflen, fh); fclose(fh); fh = NULL; memset(buf, 0, max_buflen); snprintf(buf, max_buflen-1, "gpg --output %s -d %s", verify_file, result_file); system(buf); memset(buf, 0, max_buflen); fh = fopen(verify_file, "rb"); if(!fh) return bang_ ("failed to open verify_file"); buflen = fread(buf, sizeof(char), max_buflen, fh); fclose(fh); if(buflen < 1 || buflen == max_buflen) return bang_ ("Failed to read result file"); #ifdef INSERT_FAILURE buf[buflen-1] = '\0'; #endif if (strncmp(buf, plaintext, strlen(plaintext)) != 0) return bang_ ("Decrypted text is different from original plaintext"); return 0; }
/** * Check the PGP signature for the given file path. * If base64_sig is provided, it will be used as the signature data after * decoding. If base64_sig is NULL, expect a signature file next to path * (e.g. "%s.sig"). * * The return value will be 0 if nothing abnormal happened during the signature * check, and -1 if an error occurred while checking signatures or if a * signature could not be found; pm_errno will be set. Note that "abnormal" * does not include a failed signature; the value in #result should be checked * to determine if the signature(s) are good. * @param handle the context handle * @param path the full path to a file * @param base64_sig optional PGP signature data in base64 encoding * @result * @return 0 in normal cases, -1 if the something failed in the check process */ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, const char *base64_sig, alpm_sigresult_t *result) { int ret = -1, sigcount; gpgme_error_t err; gpgme_ctx_t ctx; gpgme_data_t filedata, sigdata; gpgme_verify_result_t verify_result; gpgme_signature_t gpgsig; char *sigpath = NULL; unsigned char *decoded_sigdata = NULL; FILE *file = NULL, *sigfile = NULL; if(!path || access(path, R_OK) != 0) { RET_ERR(handle, ALPM_ERR_NOT_A_FILE, -1); } if(!result) { RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1); } result->count = 0; if(!base64_sig) { size_t len = strlen(path) + 5; CALLOC(sigpath, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(sigpath, len, "%s.sig", path); if(!access(sigpath, R_OK) == 0) { /* sigcount is 0 */ } } if(init_gpgme(handle)) { /* pm_errno was set in gpgme_init() */ return -1; } _alpm_log(handle, ALPM_LOG_DEBUG, "checking signature for %s\n", path); memset(&ctx, 0, sizeof(ctx)); memset(&sigdata, 0, sizeof(sigdata)); memset(&filedata, 0, sizeof(filedata)); err = gpgme_new(&ctx); CHECK_ERR(); /* create our necessary data objects to verify the signature */ file = fopen(path, "rb"); if(file == NULL) { handle->pm_errno = ALPM_ERR_NOT_A_FILE; goto error; } err = gpgme_data_new_from_stream(&filedata, file); CHECK_ERR(); /* next create data object for the signature */ if(base64_sig) { /* memory-based, we loaded it from a sync DB */ int data_len; int decode_ret = decode_signature(base64_sig, &decoded_sigdata, &data_len); if(decode_ret) { handle->pm_errno = ALPM_ERR_SIG_INVALID; goto error; } err = gpgme_data_new_from_mem(&sigdata, (char *)decoded_sigdata, data_len, 0); } else { /* file-based, it is on disk */ sigfile = fopen(sigpath, "rb"); if(sigfile == NULL) { handle->pm_errno = ALPM_ERR_SIG_MISSING; goto error; } err = gpgme_data_new_from_stream(&sigdata, sigfile); } CHECK_ERR(); /* here's where the magic happens */ err = gpgme_op_verify(ctx, sigdata, filedata, NULL); CHECK_ERR(); verify_result = gpgme_op_verify_result(ctx); CHECK_ERR(); if(!verify_result || !verify_result->signatures) { _alpm_log(handle, ALPM_LOG_DEBUG, "no signatures returned\n"); handle->pm_errno = ALPM_ERR_SIG_MISSING; goto error; } for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig; gpgsig = gpgsig->next, sigcount++); _alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount); result->status = calloc(sigcount, sizeof(alpm_sigstatus_t)); result->uid = calloc(sigcount, sizeof(char*)); if(!result->status || !result->uid) { handle->pm_errno = ALPM_ERR_MEMORY; goto error; } result->count = sigcount; for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig; gpgsig = gpgsig->next, sigcount++) { alpm_list_t *summary_list, *summary; alpm_sigstatus_t status; gpgme_key_t key; _alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr); summary_list = list_sigsum(gpgsig->summary); for(summary = summary_list; summary; summary = summary->next) { _alpm_log(handle, ALPM_LOG_DEBUG, "summary: %s\n", (const char *)summary->data); } alpm_list_free(summary_list); _alpm_log(handle, ALPM_LOG_DEBUG, "status: %s\n", gpgme_strerror(gpgsig->status)); _alpm_log(handle, ALPM_LOG_DEBUG, "timestamp: %lu\n", gpgsig->timestamp); _alpm_log(handle, ALPM_LOG_DEBUG, "exp_timestamp: %lu\n", gpgsig->exp_timestamp); _alpm_log(handle, ALPM_LOG_DEBUG, "validity: %s; reason: %s\n", string_validity(gpgsig->validity), gpgme_strerror(gpgsig->validity_reason)); err = gpgme_get_key(ctx, gpgsig->fpr, &key, 0); if(gpg_err_code(err) == GPG_ERR_EOF) { _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n"); err = GPG_ERR_NO_ERROR; } else { CHECK_ERR(); if(key->uids) { const char *uid = key->uids->uid; STRDUP(result->uid[sigcount], uid, handle->pm_errno = ALPM_ERR_MEMORY; goto error); _alpm_log(handle, ALPM_LOG_DEBUG, "key user: %s\n", uid); } gpgme_key_unref(key); } if(gpgsig->summary & GPGME_SIGSUM_VALID) { /* definite good signature */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: valid signature\n"); status = ALPM_SIGSTATUS_VALID; } else if(gpgsig->summary & GPGME_SIGSUM_GREEN) { /* good signature */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: green signature\n"); status = ALPM_SIGSTATUS_VALID; } else if(gpgsig->summary & GPGME_SIGSUM_RED) { /* definite bad signature, error */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: red signature\n"); status = ALPM_SIGSTATUS_BAD; } else if(gpgsig->summary & GPGME_SIGSUM_KEY_MISSING) { _alpm_log(handle, ALPM_LOG_DEBUG, "result: signature from unknown key\n"); status = ALPM_SIGSTATUS_UNKNOWN; } else if(gpgsig->summary & GPGME_SIGSUM_KEY_EXPIRED) { _alpm_log(handle, ALPM_LOG_DEBUG, "result: key expired\n"); status = ALPM_SIGSTATUS_BAD; } else if(gpgsig->summary & GPGME_SIGSUM_SIG_EXPIRED) { _alpm_log(handle, ALPM_LOG_DEBUG, "result: signature expired\n"); status = ALPM_SIGSTATUS_BAD; } else { /* we'll capture everything else here */ _alpm_log(handle, ALPM_LOG_DEBUG, "result: invalid signature\n"); status = ALPM_SIGSTATUS_BAD; } result->status[sigcount] = status; } ret = 0; error: gpgme_data_release(sigdata); gpgme_data_release(filedata); gpgme_release(ctx); if(sigfile) { fclose(sigfile); } if(file) { fclose(file); } FREE(sigpath); FREE(decoded_sigdata); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { _alpm_log(handle, ALPM_LOG_ERROR, _("GPGME error: %s\n"), gpgme_strerror(err)); RET_ERR(handle, ALPM_ERR_GPGME, -1); } return ret; }
int main (int argc, char **argv) { round_t round = TEST_INITIALIZER; char *text_filename = make_filename ("t-data-1.txt"); char *longer_text_filename = make_filename ("t-data-2.txt"); const char *missing_filename = "this-file-surely-does-not-exist"; gpgme_error_t err = 0; gpgme_data_t data; while (++round) { switch (round) { case TEST_INVALID_ARGUMENT: err = gpgme_data_new (NULL); if (!err) { fprintf (stderr, "%s:%d: gpgme_data_new on NULL pointer succeeded " "unexpectedly\n", __FILE__, __LINE__); exit (1); } continue; case TEST_INOUT_NONE: err = gpgme_data_new (&data); break; case TEST_INOUT_MEM_NO_COPY: err = gpgme_data_new_from_mem (&data, text, strlen (text), 0); break; case TEST_INOUT_MEM_COPY: err = gpgme_data_new_from_mem (&data, text, strlen (text), 1); break; case TEST_INOUT_MEM_FROM_FILE_COPY: err = gpgme_data_new_from_file (&data, text_filename, 1); break; case TEST_INOUT_MEM_FROM_INEXISTANT_FILE: err = gpgme_data_new_from_file (&data, missing_filename, 1); if (!err) { fprintf (stderr, "%s:%d: gpgme_data_new_from_file on inexistant " "file succeeded unexpectedly\n", __FILE__, __LINE__); exit (1); } continue; case TEST_INOUT_MEM_FROM_FILE_NO_COPY: err = gpgme_data_new_from_file (&data, text_filename, 0); /* This is not implemented yet. */ if (gpgme_err_code (err) == GPG_ERR_NOT_IMPLEMENTED || gpgme_err_code (err) == GPG_ERR_INV_VALUE) continue; break; case TEST_INOUT_MEM_FROM_FILE_PART_BY_NAME: err = gpgme_data_new_from_filepart (&data, longer_text_filename, 0, strlen (text), strlen (text)); break; case TEST_INOUT_MEM_FROM_INEXISTANT_FILE_PART: err = gpgme_data_new_from_filepart (&data, missing_filename, 0, strlen (text), strlen (text)); if (!err) { fprintf (stderr, "%s:%d: gpgme_data_new_from_file on inexistant " "file succeeded unexpectedly\n", __FILE__, __LINE__); exit (1); } continue; case TEST_INOUT_MEM_FROM_FILE_PART_BY_FP: { FILE *fp = fopen (longer_text_filename, "rb"); if (! fp) { fprintf (stderr, "%s:%d: fopen: %s\n", __FILE__, __LINE__, strerror (errno)); exit (1); } err = gpgme_data_new_from_filepart (&data, 0, fp, strlen (text), strlen (text)); } break; case TEST_END: goto out; case TEST_INITIALIZER: /* Shouldn't happen. */ fprintf (stderr, "%s:%d: impossible condition\n", __FILE__, __LINE__); exit (1); } fail_if_err (err); read_test (round, data); write_test (round, data); gpgme_data_release (data); } out: free (text_filename); free (longer_text_filename); return 0; }
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; }
gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *from_addr) { MimeInfo *msgcontent, *sigmultipart, *newinfo; gchar *textstr, *micalg = NULL; FILE *fp; gchar *boundary = NULL; gchar *sigcontent; gpgme_ctx_t ctx; gpgme_data_t gpgtext, gpgsig; gpgme_error_t err; size_t len; struct passphrase_cb_info_s info; gpgme_sign_result_t result = NULL; gchar *test_msg; fp = my_tmpfile(); if (fp == NULL) { perror("my_tmpfile"); privacy_set_error(_("Couldn't create temporary file: %s"), g_strerror(errno)); return FALSE; } procmime_write_mimeinfo(mimeinfo, fp); rewind(fp); /* read temporary file into memory */ test_msg = file_read_stream_to_str(fp); claws_fclose(fp); memset (&info, 0, sizeof info); /* remove content node from message */ msgcontent = (MimeInfo *) mimeinfo->node->children->data; g_node_unlink(msgcontent->node); /* create temporary multipart for content */ sigmultipart = procmime_mimeinfo_new(); sigmultipart->type = MIMETYPE_MULTIPART; sigmultipart->subtype = g_strdup("signed"); do { g_free(boundary); boundary = generate_mime_boundary("Sig"); } while (strstr(test_msg, boundary) != NULL); g_free(test_msg); g_hash_table_insert(sigmultipart->typeparameters, g_strdup("boundary"), g_strdup(boundary)); g_hash_table_insert(sigmultipart->typeparameters, g_strdup("protocol"), g_strdup("application/pgp-signature")); g_node_append(sigmultipart->node, msgcontent->node); g_node_append(mimeinfo->node, sigmultipart->node); /* write message content to temporary file */ fp = my_tmpfile(); if (fp == NULL) { perror("my_tmpfile"); privacy_set_error(_("Couldn't create temporary file: %s"), g_strerror(errno)); return FALSE; } procmime_write_mimeinfo(sigmultipart, fp); rewind(fp); /* read temporary file into memory */ textstr = get_canonical_content(fp, boundary); g_free(boundary); claws_fclose(fp); gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0); gpgme_data_new(&gpgsig); if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); return FALSE; } gpgme_set_textmode(ctx, 1); gpgme_set_armor(ctx, 1); gpgme_signers_clear (ctx); if (!sgpgme_setup_signers(ctx, account, from_addr)) { gpgme_release(ctx); return FALSE; } prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent); if (g_getenv("GPG_AGENT_INFO") && prefs_gpg_get_config()->use_gpg_agent) { debug_print("GPG_AGENT_INFO environment defined, running without passphrase callback\n"); } else { info.c = ctx; gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info); } err = gpgme_op_sign(ctx, gpgtext, gpgsig, GPGME_SIG_MODE_DETACH); if (err != GPG_ERR_NO_ERROR) { if (err == GPG_ERR_CANCELED) { /* ignore cancelled signing */ privacy_reset_error(); debug_print("gpgme_op_sign cancelled\n"); } else { privacy_set_error(_("Data signing failed, %s"), gpgme_strerror(err)); debug_print("gpgme_op_sign error : %x\n", err); } gpgme_release(ctx); return FALSE; } result = gpgme_op_sign_result(ctx); if (result && result->signatures) { gpgme_new_signature_t sig = result->signatures; if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) { gchar *down_algo = g_ascii_strdown(gpgme_hash_algo_name( result->signatures->hash_algo), -1); micalg = g_strdup_printf("pgp-%s", down_algo); g_free(down_algo); } else { micalg = g_strdup(gpgme_hash_algo_name( result->signatures->hash_algo)); } while (sig) { debug_print("valid signature: %s\n", sig->fpr); sig = sig->next; } } else if (result && result->invalid_signers) { gpgme_invalid_key_t invalid = result->invalid_signers; while (invalid) { g_warning("invalid signer: %s (%s)", invalid->fpr, gpgme_strerror(invalid->reason)); privacy_set_error(_("Data signing failed due to invalid signer: %s"), gpgme_strerror(invalid->reason)); invalid = invalid->next; } gpgme_release(ctx); return FALSE; } else { /* can't get result (maybe no signing key?) */ debug_print("gpgme_op_sign_result error\n"); privacy_set_error(_("Data signing failed, no results.")); gpgme_release(ctx); return FALSE; } sigcontent = sgpgme_data_release_and_get_mem(gpgsig, &len); gpgme_data_release(gpgtext); g_free(textstr); if (sigcontent == NULL || len <= 0) { g_warning("sgpgme_data_release_and_get_mem failed"); privacy_set_error(_("Data signing failed, no contents.")); g_free(micalg); g_free(sigcontent); return FALSE; } /* add signature */ g_hash_table_insert(sigmultipart->typeparameters, g_strdup("micalg"), micalg); newinfo = procmime_mimeinfo_new(); newinfo->type = MIMETYPE_APPLICATION; newinfo->subtype = g_strdup("pgp-signature"); newinfo->description = g_strdup(_("OpenPGP digital signature")); newinfo->content = MIMECONTENT_MEM; newinfo->data.mem = g_malloc(len + 1); g_memmove(newinfo->data.mem, sigcontent, len); newinfo->data.mem[len] = '\0'; g_node_append(sigmultipart->node, newinfo->node); g_free(sigcontent); gpgme_release(ctx); return TRUE; }
/* ------------------ * 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; }
gboolean pgpmime_encrypt(MimeInfo *mimeinfo, const gchar *encrypt_data) { MimeInfo *msgcontent, *encmultipart, *newinfo; FILE *fp; gchar *boundary, *enccontent; size_t len; gchar *textstr; gpgme_data_t gpgtext = NULL, gpgenc = NULL; gpgme_ctx_t ctx = NULL; gpgme_key_t *kset = NULL; gchar **fprs = g_strsplit(encrypt_data, " ", -1); gint i = 0; gpgme_error_t err; while (fprs[i] && strlen(fprs[i])) { i++; } kset = g_malloc(sizeof(gpgme_key_t)*(i+1)); memset(kset, 0, sizeof(gpgme_key_t)*(i+1)); if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); g_free(kset); return FALSE; } i = 0; while (fprs[i] && strlen(fprs[i])) { gpgme_key_t key; err = gpgme_get_key(ctx, fprs[i], &key, 0); if (err) { debug_print("can't add key '%s'[%d] (%s)\n", fprs[i],i, gpgme_strerror(err)); privacy_set_error(_("Couldn't add GPG key %s, %s"), fprs[i], gpgme_strerror(err)); g_free(kset); return FALSE; } debug_print("found %s at %d\n", fprs[i], i); kset[i] = key; i++; } debug_print("Encrypting message content\n"); /* remove content node from message */ msgcontent = (MimeInfo *) mimeinfo->node->children->data; g_node_unlink(msgcontent->node); /* create temporary multipart for content */ encmultipart = procmime_mimeinfo_new(); encmultipart->type = MIMETYPE_MULTIPART; encmultipart->subtype = g_strdup("encrypted"); boundary = generate_mime_boundary("Encrypt"); g_hash_table_insert(encmultipart->typeparameters, g_strdup("boundary"), g_strdup(boundary)); g_hash_table_insert(encmultipart->typeparameters, g_strdup("protocol"), g_strdup("application/pgp-encrypted")); g_node_append(encmultipart->node, msgcontent->node); /* write message content to temporary file */ fp = my_tmpfile(); if (fp == NULL) { perror("my_tmpfile"); privacy_set_error(_("Couldn't create temporary file, %s"), g_strerror(errno)); g_free(kset); return FALSE; } procmime_write_mimeinfo(encmultipart, fp); rewind(fp); /* read temporary file into memory */ textstr = get_canonical_content(fp, boundary); g_free(boundary); claws_fclose(fp); /* encrypt data */ gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0); gpgme_data_new(&gpgenc); gpgme_set_armor(ctx, 1); cm_gpgme_data_rewind(gpgtext); err = gpgme_op_encrypt(ctx, kset, GPGME_ENCRYPT_ALWAYS_TRUST, gpgtext, gpgenc); enccontent = sgpgme_data_release_and_get_mem(gpgenc, &len); gpgme_data_release(gpgtext); g_free(textstr); g_free(kset); if (enccontent == NULL || len <= 0) { g_warning("sgpgme_data_release_and_get_mem failed"); privacy_set_error(_("Encryption failed, %s"), gpgme_strerror(err)); gpgme_release(ctx); g_free(enccontent); return FALSE; } /* create encrypted multipart */ g_node_unlink(msgcontent->node); procmime_mimeinfo_free_all(&msgcontent); g_node_append(mimeinfo->node, encmultipart->node); newinfo = procmime_mimeinfo_new(); newinfo->type = MIMETYPE_APPLICATION; newinfo->subtype = g_strdup("pgp-encrypted"); newinfo->content = MIMECONTENT_MEM; newinfo->data.mem = g_strdup("Version: 1\n"); g_node_append(encmultipart->node, newinfo->node); newinfo = procmime_mimeinfo_new(); newinfo->type = MIMETYPE_APPLICATION; newinfo->subtype = g_strdup("octet-stream"); newinfo->content = MIMECONTENT_MEM; newinfo->data.mem = g_malloc(len + 1); g_memmove(newinfo->data.mem, enccontent, len); newinfo->data.mem[len] = '\0'; g_node_append(encmultipart->node, newinfo->node); g_free(enccontent); gpgme_release(ctx); return TRUE; }
static retvalue extract_signed_data(const char *buffer, size_t bufferlen, const char *filenametoshow, char **chunkread, /*@null@*/ /*@out@*/struct signatures **signatures_p, bool *brokensignature) { char *chunk; gpg_error_t err; gpgme_data_t dh, dh_gpg; size_t plain_len; char *plain_data; retvalue r; struct signatures *signatures = NULL; bool foundbroken = false; r = signature_init(false); if (RET_WAS_ERROR(r)) return r; err = gpgme_data_new_from_mem(&dh_gpg, buffer, bufferlen, 0); if (err != 0) return gpgerror(err); err = gpgme_data_new(&dh); if (err != 0) { gpgme_data_release(dh_gpg); return gpgerror(err); } err = gpgme_op_verify(context, dh_gpg, NULL, dh); if (gpg_err_code(err) == GPG_ERR_NO_DATA) { if (verbose > 5) fprintf(stderr, "Data seems not to be signed trying to use directly....\n"); gpgme_data_release(dh); gpgme_data_release(dh_gpg); return RET_NOTHING; } else { if (err != 0) { gpgme_data_release(dh_gpg); gpgme_data_release(dh); return gpgerror(err); } if (signatures_p != NULL || brokensignature != NULL) { r = checksigs(filenametoshow, (signatures_p!=NULL)?&signatures:NULL, (brokensignature!=NULL)?&foundbroken:NULL); if (RET_WAS_ERROR(r)) { gpgme_data_release(dh_gpg); gpgme_data_release(dh); return r; } } gpgme_data_release(dh_gpg); plain_data = gpgme_data_release_and_get_mem(dh, &plain_len); if (plain_data == NULL) { fprintf(stderr, "(not yet fatal) ERROR: libgpgme failed to extract the plain data out of\n" "'%s'.\n" "While it did so in a way indicating running out of memory, experience says\n" "this also happens when gpg returns a error code it does not understand.\n" "To check this please try running gpg --verify '%s' manually.\n" "Continuing extracting it ignoring all signatures...", filenametoshow, filenametoshow); signatures_free(signatures); return RET_NOTHING; } if (signatures != NULL) { r = check_primary_keys(signatures); if (RET_WAS_ERROR(r)) { signatures_free(signatures); return r; } } } if (FAILEDTOALLOC(plain_data)) r = RET_ERROR_OOM; else { size_t len; const char *afterchanges; chunk = malloc(plain_len + 1); len = chunk_extract(chunk, plain_data, plain_len, false, &afterchanges); if (len == 0) { fprintf(stderr, "Could only find spaces within '%s'!\n", filenametoshow); free(chunk); r = RET_ERROR; } else if (afterchanges != plain_data + plain_len) { if (*afterchanges == '\0') fprintf(stderr, "Unexpected \\0 character within '%s'!\n", filenametoshow); else fprintf(stderr, "Unexpected data after ending empty line in '%s'!\n", filenametoshow); free(chunk); r = RET_ERROR; } else *chunkread = chunk; } #ifdef HAVE_GPGPME_FREE gpgme_free(plain_data); #else free(plain_data); #endif if (RET_IS_OK(r)) { if (signatures_p != NULL) *signatures_p = signatures; if (brokensignature != NULL) *brokensignature = foundbroken; } else { signatures_free(signatures); } return r; }
/* ------------------ * 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_key_t sender_key; gpgme_data_t plain,cipher; char* cipher_str = NULL; char* cipher_str_dup = NULL; size_t len; gpgme_key_t key_arr[3]; key_arr[0] = NULL; key_arr[1] = NULL; key_arr[2] = 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; // check if user selected a main key const char* sender_fpr = purple_prefs_get_string(PREF_MY_KEY); if ( sender_fpr != NULL && strcmp(sender_fpr,"") != 0) { // get own key by fingerprint error = gpgme_get_key(ctx,sender_fpr,&sender_key,0); if (!error && sender_key) key_arr[1] = sender_key; else purple_debug_error(PLUGIN_ID,"gpgme_get_key: sender key for fingerprint %s is missing! error: %s %s\n", sender_fpr, gpgme_strsource (error), gpgme_strerror (error) ); } else purple_debug_error(PLUGIN_ID,"purple_prefs_get_string: PREF_MY_KEY was empty\n"); // 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; }
/* Loop through all files in metalink structure and retrieve them. Returns RETROK if all files were downloaded. Returns last retrieval error (from retrieve_url) if some files could not be downloaded. */ uerr_t retrieve_from_metalink (const metalink_t* metalink) { metalink_file_t **mfile_ptr; uerr_t last_retr_err = RETROK; /* Store last encountered retrieve error. */ FILE *_output_stream = output_stream; bool _output_stream_regular = output_stream_regular; char *_output_document = opt.output_document; DEBUGP (("Retrieving from Metalink\n")); /* No files to download. */ if (!metalink->files) return RETROK; if (opt.output_document) { /* We cannot support output_document as we need to compute checksum of downloaded file, and to remove it if the checksum is bad. */ logputs (LOG_NOTQUIET, _("-O not supported for metalink download. Ignoring.\n")); } for (mfile_ptr = metalink->files; *mfile_ptr; mfile_ptr++) { metalink_file_t *mfile = *mfile_ptr; metalink_resource_t **mres_ptr; char *filename = NULL; bool hash_ok = false; uerr_t retr_err = METALINK_MISSING_RESOURCE; /* -1 -> file should be rejected 0 -> could not verify 1 -> verified successfully */ char sig_status = 0; output_stream = NULL; DEBUGP (("Processing metalink file %s...\n", quote (mfile->name))); /* Resources are sorted by priority. */ for (mres_ptr = mfile->resources; *mres_ptr; mres_ptr++) { metalink_resource_t *mres = *mres_ptr; metalink_checksum_t **mchksum_ptr, *mchksum; struct iri *iri; struct url *url; int url_err; if (!RES_TYPE_SUPPORTED (mres->type)) { logprintf (LOG_VERBOSE, _("Resource type %s not supported, ignoring...\n"), quote (mres->type)); continue; } retr_err = METALINK_RETR_ERROR; /* If output_stream is not NULL, then we have failed on previous resource and are retrying. Thus, remove the file. */ if (output_stream) { fclose (output_stream); output_stream = NULL; if (unlink (filename)) logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno)); xfree (filename); } /* Parse our resource URL. */ iri = iri_new (); set_uri_encoding (iri, opt.locale, true); url = url_parse (mres->url, &url_err, iri, false); if (!url) { char *error = url_error (mres->url, url_err); logprintf (LOG_NOTQUIET, "%s: %s.\n", mres->url, error); xfree (error); inform_exit_status (URLERROR); iri_free (iri); continue; } else { /* Avoid recursive Metalink from HTTP headers. */ bool _metalink_http = opt.metalink_over_http; /* Assure proper local file name regardless of the URL of particular Metalink resource. To do that we create the local file here and put it as output_stream. We restore the original configuration after we are finished with the file. */ output_stream = unique_create (mfile->name, true, &filename); output_stream_regular = true; /* Store the real file name for displaying in messages. */ opt.output_document = filename; opt.metalink_over_http = false; DEBUGP (("Storing to %s\n", filename)); retr_err = retrieve_url (url, mres->url, NULL, NULL, NULL, NULL, opt.recursive, iri, false); opt.metalink_over_http = _metalink_http; } url_free (url); iri_free (iri); if (retr_err == RETROK) { FILE *local_file; /* Check the digest. */ local_file = fopen (filename, "rb"); if (!local_file) { logprintf (LOG_NOTQUIET, _("Could not open downloaded file.\n")); continue; } for (mchksum_ptr = mfile->checksums; *mchksum_ptr; mchksum_ptr++) { char sha256[SHA256_DIGEST_SIZE]; char sha256_txt[2 * SHA256_DIGEST_SIZE + 1]; mchksum = *mchksum_ptr; /* I have seen both variants... */ if (strcasecmp (mchksum->type, "sha256") && strcasecmp (mchksum->type, "sha-256")) { DEBUGP (("Ignoring unsupported checksum type %s.\n", quote (mchksum->type))); continue; } logprintf (LOG_VERBOSE, _("Computing checksum for %s\n"), quote (mfile->name)); sha256_stream (local_file, sha256); wg_hex_to_string (sha256_txt, sha256, SHA256_DIGEST_SIZE); DEBUGP (("Declared hash: %s\n", mchksum->hash)); DEBUGP (("Computed hash: %s\n", sha256_txt)); if (!strcmp (sha256_txt, mchksum->hash)) { logputs (LOG_VERBOSE, _("Checksum matches.\n")); hash_ok = true; } else { logprintf (LOG_NOTQUIET, _("Checksum mismatch for file %s.\n"), quote (mfile->name)); hash_ok = false; } /* Stop as soon as we checked the supported checksum. */ break; } /* Iterate over available checksums. */ fclose (local_file); local_file = NULL; if (!hash_ok) continue; sig_status = 0; /* Not verified. */ #ifdef HAVE_GPGME /* Check the crypto signature. Note that the signtures from Metalink in XML will not be parsed when using libmetalink version older than 0.1.3. Metalink-over-HTTP is not affected by this problem. */ if (mfile->signature) { metalink_signature_t *msig = mfile->signature; gpgme_error_t gpgerr; gpgme_ctx_t gpgctx; gpgme_data_t gpgsigdata, gpgdata; gpgme_verify_result_t gpgres; gpgme_signature_t gpgsig; gpgme_protocol_t gpgprot = GPGME_PROTOCOL_UNKNOWN; int fd = -1; /* Initialize the library - as name suggests. */ gpgme_check_version (NULL); /* Open data file. */ fd = open (filename, O_RDONLY); if (fd == -1) { logputs (LOG_NOTQUIET, _("Could not open downloaded file for signature " "verification.\n")); goto gpg_skip_verification; } /* Assign file descriptor to GPG data structure. */ gpgerr = gpgme_data_new_from_fd (&gpgdata, fd); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME data_new_from_fd: %s\n", gpgme_strerror (gpgerr)); goto gpg_skip_verification; } /* Prepare new GPGME context. */ gpgerr = gpgme_new (&gpgctx); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME new: %s\n", gpgme_strerror (gpgerr)); gpgme_data_release (gpgdata); goto gpg_skip_verification; } DEBUGP (("Verifying signature %s:\n%s\n", quote (msig->mediatype), msig->signature)); /* Check signature type. */ if (!strcmp (msig->mediatype, "application/pgp-signature")) gpgprot = GPGME_PROTOCOL_OpenPGP; else /* Unsupported signature type. */ { gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } gpgerr = gpgme_set_protocol (gpgctx, gpgprot); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME set_protocol: %s\n", gpgme_strerror (gpgerr)); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* Load the signature. */ gpgerr = gpgme_data_new_from_mem (&gpgsigdata, msig->signature, strlen (msig->signature), 0); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, _("GPGME data_new_from_mem: %s\n"), gpgme_strerror (gpgerr)); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* Verify the signature. */ gpgerr = gpgme_op_verify (gpgctx, gpgsigdata, gpgdata, NULL); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, _("GPGME op_verify: %s\n"), gpgme_strerror (gpgerr)); gpgme_data_release (gpgsigdata); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* Check the results. */ gpgres = gpgme_op_verify_result (gpgctx); if (!gpgres) { logputs (LOG_NOTQUIET, _("GPGME op_verify_result: NULL\n")); gpgme_data_release (gpgsigdata); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* The list is null-terminated. */ for (gpgsig = gpgres->signatures; gpgsig; gpgsig = gpgsig->next) { DEBUGP (("Checking signature %s\n", gpgsig->fpr)); if (gpgsig->summary & (GPGME_SIGSUM_VALID | GPGME_SIGSUM_GREEN)) { logputs (LOG_VERBOSE, _("Signature validation suceeded.\n")); sig_status = 1; break; } if (gpgsig->summary & GPGME_SIGSUM_RED) { logputs (LOG_NOTQUIET, _("Invalid signature. Rejecting resource.\n")); sig_status = -1; break; } if (gpgsig->summary == 0 && (gpgsig->status & 0xFFFF) == GPG_ERR_NO_ERROR) { logputs (LOG_VERBOSE, _("Data matches signature, but signature " "is not trusted.\n")); } if ((gpgsig->status & 0xFFFF) != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME: %s\n", gpgme_strerror (gpgsig->status & 0xFFFF)); } } gpgme_data_release (gpgsigdata); gpgme_release (gpgctx); gpgme_data_release (gpgdata); gpg_skip_verification: if (fd != -1) close (fd); } /* endif (mfile->signature) */ #endif /* Stop if file was downloaded with success. */ if (sig_status >= 0) break; } /* endif RETR_OK. */ } /* Iterate over resources. */ if (retr_err != RETROK) { logprintf (LOG_VERBOSE, _("Failed to download %s. Skipping resource.\n"), quote (mfile->name)); } else if (!hash_ok) { retr_err = METALINK_CHKSUM_ERROR; logprintf (LOG_NOTQUIET, _("File %s retrieved but checksum does not match. " "\n"), quote (mfile->name)); } #ifdef HAVE_GPGME /* Signature will be only validated if hash check was successful. */ else if (sig_status < 0) { retr_err = METALINK_SIG_ERROR; logprintf (LOG_NOTQUIET, _("File %s retrieved but signature does not match. " "\n"), quote (mfile->name)); } #endif last_retr_err = retr_err == RETROK ? last_retr_err : retr_err; /* Remove the file if error encountered or if option specified. Note: the file has been downloaded using *_loop. Therefore, it is not necessary to keep the file for continuated download. */ if ((retr_err != RETROK || opt.delete_after) && filename != NULL && file_exists_p (filename)) { logprintf (LOG_VERBOSE, _("Removing %s.\n"), quote (filename)); if (unlink (filename)) logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno)); } if (output_stream) { fclose (output_stream); output_stream = NULL; } xfree (filename); } /* Iterate over files. */ /* Restore original values. */ opt.output_document = _output_document; output_stream_regular = _output_stream_regular; output_stream = _output_stream; return last_retr_err; }
/** * Check the PGP signature for the given file path. * If base64_sig is provided, it will be used as the signature data after * decoding. If base64_sig is NULL, expect a signature file next to path * (e.g. "%s.sig"). * * The return value will be 0 if nothing abnormal happened during the signature * check, and -1 if an error occurred while checking signatures or if a * signature could not be found; pm_errno will be set. Note that "abnormal" * does not include a failed signature; the value in siglist should be checked * to determine if the signature(s) are good. * @param handle the context handle * @param path the full path to a file * @param base64_sig optional PGP signature data in base64 encoding * @param siglist a pointer to storage for signature results * @return 0 in normal cases, -1 if the something failed in the check process */ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, const char *base64_sig, alpm_siglist_t *siglist) { int ret = -1, sigcount; gpgme_error_t err = 0; gpgme_ctx_t ctx; gpgme_data_t filedata, sigdata; gpgme_verify_result_t verify_result; gpgme_signature_t gpgsig; char *sigpath = NULL; unsigned char *decoded_sigdata = NULL; FILE *file = NULL, *sigfile = NULL; if(!path || _alpm_access(handle, NULL, path, R_OK) != 0) { RET_ERR(handle, ALPM_ERR_NOT_A_FILE, -1); } if(!siglist) { RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1); } siglist->count = 0; if(!base64_sig) { sigpath = _alpm_sigpath(handle, path); if(_alpm_access(handle, NULL, sigpath, R_OK) != 0 || (sigfile = fopen(sigpath, "rb")) == NULL) { _alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n", sigpath); handle->pm_errno = ALPM_ERR_SIG_MISSING; goto error; } } /* does the file we are verifying exist? */ file = fopen(path, "rb"); if(file == NULL) { handle->pm_errno = ALPM_ERR_NOT_A_FILE; goto error; } if(init_gpgme(handle)) { /* pm_errno was set in gpgme_init() */ goto error; } _alpm_log(handle, ALPM_LOG_DEBUG, "checking signature for %s\n", path); memset(&ctx, 0, sizeof(ctx)); memset(&sigdata, 0, sizeof(sigdata)); memset(&filedata, 0, sizeof(filedata)); err = gpgme_new(&ctx); CHECK_ERR(); /* create our necessary data objects to verify the signature */ err = gpgme_data_new_from_stream(&filedata, file); CHECK_ERR(); /* next create data object for the signature */ if(base64_sig) { /* memory-based, we loaded it from a sync DB */ size_t data_len; int decode_ret = decode_signature(base64_sig, &decoded_sigdata, &data_len); if(decode_ret) { handle->pm_errno = ALPM_ERR_SIG_INVALID; goto gpg_error; } err = gpgme_data_new_from_mem(&sigdata, (char *)decoded_sigdata, data_len, 0); } else { /* file-based, it is on disk */ err = gpgme_data_new_from_stream(&sigdata, sigfile); } CHECK_ERR(); /* here's where the magic happens */ err = gpgme_op_verify(ctx, sigdata, filedata, NULL); CHECK_ERR(); verify_result = gpgme_op_verify_result(ctx); CHECK_ERR(); if(!verify_result || !verify_result->signatures) { _alpm_log(handle, ALPM_LOG_DEBUG, "no signatures returned\n"); handle->pm_errno = ALPM_ERR_SIG_MISSING; goto gpg_error; } for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig; gpgsig = gpgsig->next, sigcount++); _alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount); CALLOC(siglist->results, sigcount, sizeof(alpm_sigresult_t), handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error); siglist->count = sigcount; for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig; gpgsig = gpgsig->next, sigcount++) { alpm_list_t *summary_list, *summary; alpm_sigstatus_t status; alpm_sigvalidity_t validity; gpgme_key_t key; alpm_sigresult_t *result; _alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr); summary_list = list_sigsum(gpgsig->summary); for(summary = summary_list; summary; summary = summary->next) { _alpm_log(handle, ALPM_LOG_DEBUG, "summary: %s\n", (const char *)summary->data); } alpm_list_free(summary_list); _alpm_log(handle, ALPM_LOG_DEBUG, "status: %s\n", gpgme_strerror(gpgsig->status)); _alpm_log(handle, ALPM_LOG_DEBUG, "timestamp: %lu\n", gpgsig->timestamp); _alpm_log(handle, ALPM_LOG_DEBUG, "exp_timestamp: %lu\n", gpgsig->exp_timestamp); _alpm_log(handle, ALPM_LOG_DEBUG, "validity: %s; reason: %s\n", string_validity(gpgsig->validity), gpgme_strerror(gpgsig->validity_reason)); result = siglist->results + sigcount; err = gpgme_get_key(ctx, gpgsig->fpr, &key, 0); if(gpg_err_code(err) == GPG_ERR_EOF) { _alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n"); err = GPG_ERR_NO_ERROR; /* we dupe the fpr in this case since we have no key to point at */ STRDUP(result->key.fingerprint, gpgsig->fpr, handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error); } else {
/** * seahorse_service_crypto_verify_text: * @crypto: #SeahorseServiceCrypto context * @ktype: "openpgp" * @flags: FLAG_QUIET for no notification * @crypttext: the text to decrypt * @cleartext: the plaintext after verification (out) * @signer: the signer if the text is signed (out) * @error: a potential error (out) * * DBus: VerifyText * * Decrypts the @crypttext and returns it in @cleartext. If the text * was signed, the signed is returned. * * Returns: TRUE on success */ gboolean seahorse_service_crypto_verify_text (SeahorseServiceCrypto *crypto, const gchar *ktype, int flags, const gchar *crypttext, gchar **cleartext, char **signer, GError **error) { gpgme_verify_result_t status; gpgme_error_t gerr; SeahorseGpgmeOperation *pop; gpgme_data_t plain, cipher; gboolean ret = TRUE; GQuark keyid; if (!g_str_equal (ktype, g_quark_to_string (SEAHORSE_PGP))) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid key type for verifying: %s"), ktype); return FALSE; } /* * TODO: Once we support different kinds of keys that support encryption * then all this logic will need to change. */ pop = seahorse_gpgme_operation_new (NULL); /* new data from text */ gerr = gpgme_data_new_from_mem (&cipher, crypttext, strlen (crypttext), FALSE); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); gerr = gpgme_data_new (&plain); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); /* encrypt with armor */ gpgme_set_textmode (pop->gctx, TRUE); gpgme_set_armor (pop->gctx, TRUE); /* Do the decryption */ gerr = gpgme_op_verify_start (pop->gctx, cipher, NULL, plain); /* Frees plain */ ret = process_crypto_result (pop, gerr, plain, cleartext, NULL, error); if (ret) { *signer = NULL; status = gpgme_op_verify_result (pop->gctx); if (status->signatures) { if (!(flags & FLAG_QUIET)) notify_signatures (NULL, status); if (status->signatures->summary & GPGME_SIGSUM_GREEN || status->signatures->summary & GPGME_SIGSUM_VALID || status->signatures->summary & GPGME_SIGSUM_KEY_MISSING) { keyid = seahorse_pgp_key_canonize_id (status->signatures->fpr); *signer = seahorse_context_id_to_dbus (SCTX_APP (), keyid); } } } g_object_unref (pop); gpgme_data_release (cipher); return TRUE; }
/** * crypto: the crypto service (#SeahorseServiceCrypto) * recipients: A list of recipients (keyids "openpgp:B8098FB063E2C811") * signer: optional, the keyid of the signer * flags: 0, not used * cleartext: the text to encrypt * clearlength: Length of the cleartext * crypttext: the encrypted text (out) * cryptlength: the length of this text (out) * textmode: TRUE if gpgme should use textmode * ascii_armor: TRUE if GPGME should use ascii armor * error: The Error * * Handles encryption in a generic way. Can be used by several DBus APIs * * Returns TRUE on success **/ static gboolean crypto_encrypt_generic (SeahorseServiceCrypto *crypto, const char **recipients, const char *signer, int flags, const char *cleartext, gsize clearlength, char **crypttext, gsize *cryptlength, gboolean textmode, gboolean ascii_armor, GError **error) { GList *recipkeys = NULL; SeahorseGpgmeOperation *pop; SeahorseObject *signkey = NULL; SeahorseObject *skey; gpgme_key_t *recips; gpgme_data_t plain, cipher; gpgme_error_t gerr; gboolean ret = TRUE; /* * TODO: Once we support different kinds of keys that support encryption * then all this logic will need to change. */ /* The signer */ if (signer && signer[0]) { signkey = seahorse_context_object_from_dbus (SCTX_APP (), signer); if (!signkey) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized signer: %s"), signer); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (signkey) || !(seahorse_object_get_flags (signkey) & SEAHORSE_FLAG_CAN_SIGN)) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not valid for signing: %s"), signer); return FALSE; } } /* The recipients */ for( ; recipients[0]; recipients++) { skey = seahorse_context_object_from_dbus (SCTX_APP (), recipients[0]); if (!skey) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Invalid or unrecognized recipient: %s"), recipients[0]); return FALSE; } if (!SEAHORSE_IS_GPGME_KEY (skey) || !(seahorse_object_get_flags (skey) & SEAHORSE_FLAG_CAN_ENCRYPT)) { g_list_free (recipkeys); g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("Key is not a valid recipient for encryption: %s"), recipients[0]); return FALSE; } recipkeys = g_list_prepend (recipkeys, SEAHORSE_PGP_KEY (skey)); } if (!recipkeys) { g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID, _("No recipients specified")); return FALSE; } pop = seahorse_gpgme_operation_new (NULL); /* new data form text */ gerr = gpgme_data_new_from_mem (&plain, cleartext, clearlength, FALSE); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); gerr = gpgme_data_new (&cipher); g_return_val_if_fail (GPG_IS_OK (gerr), FALSE); /* encrypt with armor */ gpgme_set_textmode (pop->gctx, textmode); gpgme_set_armor (pop->gctx, ascii_armor); /* Add the default key if set and necessary */ if (seahorse_gconf_get_boolean (ENCRYPTSELF_KEY)) { skey = SEAHORSE_OBJECT (seahorse_context_get_default_key (SCTX_APP ())); if (SEAHORSE_IS_PGP_KEY (skey)) recipkeys = g_list_append (recipkeys, skey); } /* Make keys into the right format for GPGME */ recips = keylist_to_keys (recipkeys); g_list_free (recipkeys); /* Do the encryption */ if (signkey) { gpgme_signers_add (pop->gctx, seahorse_gpgme_key_get_private (SEAHORSE_GPGME_KEY (signkey))); gerr = gpgme_op_encrypt_sign_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } else { gerr = gpgme_op_encrypt_start (pop->gctx, recips, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); } free_keys (recips); /* Frees cipher */ ret = process_crypto_result (pop, gerr, cipher, crypttext, cryptlength, error); g_object_unref (pop); gpgme_data_release (plain); return ret; }
QString QalfCrypto::sign(QString &message, QString &key) { gpgme_key_t gpgkey ; gpgme_data_t signature ; gpgme_data_t msg ; gpgme_verify_result_t verification ; gpgme_signature_t signatures ; gpgme_error_t result ; char * buffer ; gpgme_set_passphrase_cb(context,&passphrase_callback,NULL) ; result = gpgme_set_protocol(context,GPGME_PROTOCOL_OpenPGP) ; Q_ASSERT(gpgme_err_code(result) == GPG_ERR_NO_ERROR) ; gpgme_set_armor(context,1) ; gpgme_set_textmode(context,1) ; gpgme_signers_clear(context) ; result = gpgme_set_keylist_mode(context,GPGME_KEYLIST_MODE_LOCAL) ; // retrieving key result = gpgme_get_key(context, key.toAscii().data(),&gpgkey,1) ; Q_ASSERT(result == GPG_ERR_NO_ERROR) ; Q_ASSERT(gpgkey != 0) ; // signing result = gpgme_signers_add(context,gpgkey) ; Q_ASSERT(result == GPG_ERR_NO_ERROR) ; result = gpgme_data_new(&signature); Q_ASSERT(result == GPG_ERR_NO_ERROR) ; int message_length = message.toAscii().size() ; char * message_char = (char *) calloc(message_length+1,sizeof(char)) ; memcpy(message_char,message.toAscii().data(),message_length) ; // printf("memcmp : %d\n",memcmp(message_char,"1fc36e1d41a93c1d79f6872198f426129320d287",message_length+1)) ; result = gpgme_data_new_from_mem(&msg,message_char,message_length,0) ; gpgme_data_seek(signature,0,SEEK_SET) ; gpgme_data_seek(msg,0,SEEK_SET) ; result = gpgme_op_sign(context, msg,signature, GPGME_SIG_MODE_DETACH) ; Q_ASSERT(gpgme_err_code(result) == GPG_ERR_NO_ERROR || gpgme_err_code(result) == GPG_ERR_BAD_PASSPHRASE || gpgme_err_code(result) == GPG_ERR_CANCELED) ; // gpgme_data_seek(signature,0,SEEK_SET) ; // gpgme_data_seek(msg,0,SEEK_SET) ; // // result = gpgme_op_verify (context, signature, msg , 0) ; // Q_ASSERT(gpgme_err_code(result) != GPG_ERR_INV_VALUE) ; // Q_ASSERT(gpgme_err_code(result) != GPG_ERR_NO_DATA) ; // Q_ASSERT(result == GPG_ERR_NO_ERROR) ; // // verification = gpgme_op_verify_result(context) ; // Q_ASSERT(verification != 0) ; // // signatures = verification->signatures ; // Q_ASSERT(verification->signatures != 0) ; // result = signatures->status ; // printf("status : %d\n",gpgme_err_code(result)) ; // printf("signature summary : %d\n",signatures->summary) ; // Q_ASSERT(signatures->summary == GPGME_SIGSUM_VALID | GPGME_SIGSUM_GREEN) ; // QString signatureStr ; buffer = (char *) calloc(2048,sizeof(char)) ; gpgme_data_seek(signature,0,SEEK_SET) ; gpgme_data_read(signature,buffer,2048) ; signatureStr += buffer ; qDebug() << "signature" << signatureStr ; gpgme_data_release(signature) ; gpgme_key_unref(gpgkey) ; gpgme_data_release(msg) ; return signatureStr ; }
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; }
/* The main GPG decryption routine for libfko. */ int gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const char *pw, unsigned char **out, size_t *out_len) { char *tmp_buf; int res; gpgme_ctx_t gpg_ctx = NULL; gpgme_data_t cipher = NULL; gpgme_data_t plaintext = NULL; gpgme_error_t err; gpgme_decrypt_result_t decrypt_res; gpgme_verify_result_t verify_res; /* Initialize gpgme */ res = init_gpgme(fko_ctx); if(res != FKO_SUCCESS) return(res); gpg_ctx = fko_ctx->gpg_ctx; err = gpgme_data_new(&plaintext); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ); } /* Initialize the cipher data (place into gpgme_data object) */ err = gpgme_data_new_from_mem(&cipher, (char*)indata, in_len, 0); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ); } /* Set the passphrase callback. */ gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw); /* Now decrypt and verify. */ err = gpgme_op_decrypt_verify(gpg_ctx, cipher, plaintext); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_data_release(cipher); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_DECRYPT_FAILED); } /* Done with the cipher text. */ gpgme_data_release(cipher); /* We check the "usupported_algorithm" flag in the decrypt result. */ decrypt_res = gpgme_op_decrypt_result(gpg_ctx); if(decrypt_res->unsupported_algorithm) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; return(FKO_ERROR_GPGME_DECRYPT_UNSUPPORTED_ALGORITHM); } /* Now verify the signatures if so configured. */ if(fko_ctx->verify_gpg_sigs) { verify_res = gpgme_op_verify_result(gpg_ctx); res = process_sigs(fko_ctx, verify_res); if(res != FKO_SUCCESS) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; return(res); } } /* Get the encrypted data and its length from the gpgme data object. */ tmp_buf = gpgme_data_release_and_get_mem(plaintext, out_len); /* Use calloc here with an extra byte because I am not sure if all systems * will include the terminating NULL with the decrypted data (which is * expected to be a string). */ *out = calloc(1, *out_len+1); /* This is freed upon fko_ctx destruction. */ if(*out == NULL) res = FKO_ERROR_MEMORY_ALLOCATION; else { memcpy(*out, tmp_buf, *out_len); res = FKO_SUCCESS; } gpgme_free(tmp_buf); return(res); }
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; }
static MimeInfo *pgpinline_decrypt(MimeInfo *mimeinfo) { MimeInfo *decinfo, *parseinfo; gpgme_data_t cipher, plain; FILE *dstfp; gchar *fname; gchar *textdata = NULL; static gint id = 0; const gchar *src_codeset = NULL; gpgme_verify_result_t sigstat = 0; PrivacyDataPGP *data = NULL; gpgme_ctx_t ctx; gchar *chars; size_t len; const gchar *begin_indicator = "-----BEGIN PGP MESSAGE-----"; const gchar *end_indicator = "-----END PGP MESSAGE-----"; gchar *pos; if (gpgme_new(&ctx) != GPG_ERR_NO_ERROR) return NULL; gpgme_set_textmode(ctx, 1); gpgme_set_armor(ctx, 1); cm_return_val_if_fail(mimeinfo != NULL, NULL); cm_return_val_if_fail(pgpinline_is_encrypted(mimeinfo), NULL); if (procmime_mimeinfo_parent(mimeinfo) == NULL || mimeinfo->type != MIMETYPE_TEXT) { gpgme_release(ctx); privacy_set_error(_("Couldn't parse mime part.")); return NULL; } textdata = get_part_as_string(mimeinfo); if (!textdata) { gpgme_release(ctx); privacy_set_error(_("Couldn't get text data.")); return NULL; } debug_print("decrypting '%s'\n", textdata); gpgme_data_new_from_mem(&cipher, textdata, (size_t)strlen(textdata), 1); plain = sgpgme_decrypt_verify(cipher, &sigstat, ctx); if (sigstat && !sigstat->signatures) sigstat = NULL; gpgme_data_release(cipher); if (plain == NULL) { gpgme_release(ctx); return NULL; } fname = g_strdup_printf("%s%cplaintext.%08x", get_mime_tmp_dir(), G_DIR_SEPARATOR, ++id); if ((dstfp = g_fopen(fname, "wb")) == NULL) { FILE_OP_ERROR(fname, "fopen"); privacy_set_error(_("Couldn't open decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; } src_codeset = procmime_mimeinfo_get_parameter(mimeinfo, "charset"); if (src_codeset == NULL) src_codeset = CS_ISO_8859_1; if (fprintf(dstfp, "MIME-Version: 1.0\r\n" "Content-Type: text/plain; charset=%s\r\n" "Content-Transfer-Encoding: 8bit\r\n" "\r\n", src_codeset) < 0) { FILE_OP_ERROR(fname, "fprintf"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } /* Store any part before encrypted text */ pos = pgp_locate_armor_header(textdata, begin_indicator); if (pos != NULL && (pos - textdata) > 0) { if (fwrite(textdata, 1, pos - textdata, dstfp) < pos - textdata) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } if (fwrite(_("\n--- Start of PGP/Inline encrypted data ---\n"), 1, strlen(_("\n--- Start of PGP/Inline encrypted data ---\n")), dstfp) < strlen(_("\n--- Start of PGP/Inline encrypted data ---\n"))) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } chars = sgpgme_data_release_and_get_mem(plain, &len); if (len > 0) { if (fwrite(chars, 1, len, dstfp) < len) { FILE_OP_ERROR(fname, "fwrite"); g_free(chars); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } g_free(chars); /* Store any part after encrypted text */ if (fwrite(_("--- End of PGP/Inline encrypted data ---\n"), 1, strlen(_("--- End of PGP/Inline encrypted data ---\n")), dstfp) < strlen(_("--- End of PGP/Inline encrypted data ---\n"))) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } if (pos != NULL) { pos = pgp_locate_armor_header(pos, end_indicator); if (pos != NULL && *pos != '\0') { pos += strlen(end_indicator); if (fwrite(pos, 1, strlen(pos), dstfp) < strlen(pos)) { FILE_OP_ERROR(fname, "fwrite"); privacy_set_error(_("Couldn't write to decrypted file %s"), fname); goto FILE_ERROR; } } } if (fclose(dstfp) == EOF) { FILE_OP_ERROR(fname, "fclose"); privacy_set_error(_("Couldn't close decrypted file %s"), fname); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; } parseinfo = procmime_scan_file(fname); g_free(fname); if (parseinfo == NULL) { gpgme_release(ctx); privacy_set_error(_("Couldn't scan decrypted file.")); return NULL; } decinfo = g_node_first_child(parseinfo->node) != NULL ? g_node_first_child(parseinfo->node)->data : NULL; if (decinfo == NULL) { gpgme_release(ctx); privacy_set_error(_("Couldn't scan decrypted file parts.")); return NULL; } g_node_unlink(decinfo->node); procmime_mimeinfo_free_all(parseinfo); decinfo->tmp = TRUE; if (sigstat != GPGME_SIG_STAT_NONE) { if (decinfo->privacy != NULL) { data = (PrivacyDataPGP *) decinfo->privacy; } else { data = pgpinline_new_privacydata(); decinfo->privacy = (PrivacyData *) data; } if (data != NULL) { data->done_sigtest = TRUE; data->is_signed = TRUE; data->sigstatus = sigstat; if (data->ctx) gpgme_release(data->ctx); data->ctx = ctx; } } else gpgme_release(ctx); return decinfo; FILE_ERROR: fclose(dstfp); g_free(fname); gpgme_data_release(plain); gpgme_release(ctx); return NULL; }
gboolean fu_keyring_verify_data (FuKeyring *keyring, GBytes *payload, GBytes *payload_signature, GError **error) { FuKeyringPrivate *priv = GET_PRIVATE (keyring); gpgme_error_t rc; gpgme_signature_t s; gpgme_verify_result_t result; g_auto(gpgme_data_t) data = NULL; g_auto(gpgme_data_t) sig = NULL; g_return_val_if_fail (FU_IS_KEYRING (keyring), FALSE); g_return_val_if_fail (payload != NULL, FALSE); g_return_val_if_fail (payload_signature != NULL, FALSE); /* setup context */ if (!fu_keyring_setup (keyring, error)) return FALSE; /* load file data */ rc = gpgme_data_new_from_mem (&data, g_bytes_get_data (payload, NULL), g_bytes_get_size (payload), 0); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load data: %s", gpgme_strerror (rc)); return FALSE; } rc = gpgme_data_new_from_mem (&sig, g_bytes_get_data (payload_signature, NULL), g_bytes_get_size (payload_signature), 0); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to load signature: %s", gpgme_strerror (rc)); return FALSE; } /* verify */ rc = gpgme_op_verify (priv->ctx, sig, data, NULL); if (rc != GPG_ERR_NO_ERROR) { g_set_error (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "failed to verify data: %s", gpgme_strerror (rc)); return FALSE; } /* verify the result */ result = gpgme_op_verify_result (priv->ctx); if (result == NULL) { g_set_error_literal (error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "no result record from libgpgme"); return FALSE; } /* look at each signature */ for (s = result->signatures; s != NULL ; s = s->next ) { g_debug ("returned signature fingerprint %s", s->fpr); if (!fu_keyring_check_signature (s, error)) return FALSE; } return TRUE; }