Browse Source

Implement partial support for detached signature.

Allow to verify detached signature, but only by assuming the
corresponding signed text is in a file with the same basename
than the signature itself, minus the '.sig', '.asc',  or '.gpg'
extension. If such a file does not exist, abort.
master
parent
commit
6f9fa43987
  1. 107
      src/decrypt.c
  2. 1
      src/errors.h
  3. 2
      src/yki-decrypt.ui

107
src/decrypt.c

@ -46,6 +46,7 @@ typedef struct {
gboolean output_filename_userset;
gboolean signed_only;
gboolean detached_signature;
} yki_decrypt_data_t;
static void
@ -119,11 +120,6 @@ create_decrypt_dialog(yki_decrypt_data_t *yki)
builder = gtk_builder_new_from_resource("/org/incenp/Yorkie/yki-decrypt.ui");
widget = gtk_builder_get_object(builder, "btnOutput");
g_signal_connect(widget, "clicked", G_CALLBACK(output_clicked), yki);
gtk_button_set_label(GTK_BUTTON(widget), yki->output_basename);
gtk_button_set_always_show_image(GTK_BUTTON(widget), TRUE);
if ( ! yki->signed_only )
gtk_label_set_label(GTK_LABEL(gtk_builder_get_object(builder, "lblDecrypt")),
"The message was successfully decrypted.");
@ -167,6 +163,17 @@ create_decrypt_dialog(yki_decrypt_data_t *yki)
}
}
if ( yki->detached_signature ) {
gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(builder, "frmOutput")), FALSE);
gtk_widget_set_visible(GTK_WIDGET(gtk_builder_get_object(builder, "btnCancel")), FALSE);
}
else {
widget = gtk_builder_get_object(builder, "btnOutput");
g_signal_connect(widget, "clicked", G_CALLBACK(output_clicked), yki);
gtk_button_set_label(GTK_BUTTON(widget), yki->output_basename);
gtk_button_set_always_show_image(GTK_BUTTON(widget), TRUE);
}
return GTK_DIALOG(gtk_builder_get_object(builder, "dlgDecrypt"));
}
@ -175,7 +182,7 @@ create_decrypt_dialog(yki_decrypt_data_t *yki)
/* Crypto helper functions. */
static int
is_file_encrypted(gpgme_data_t buffer, GError **error)
identify_input(yki_decrypt_data_t *yki, gpgme_data_t buffer, GError **error)
{
int ret;
gpgme_data_type_t type;
@ -197,8 +204,8 @@ is_file_encrypted(gpgme_data_t buffer, GError **error)
break;
case GPGME_DATA_TYPE_PGP_SIGNATURE:
yki_error(error, YKI_ERROR_NOT_IMPLEMENTED, "Cannot verify detached signature");
ret = 0;
yki->detached_signature = TRUE;
ret = 1;
break;
case GPGME_DATA_TYPE_PGP_SIGNED:
@ -211,6 +218,51 @@ is_file_encrypted(gpgme_data_t buffer, GError **error)
return ret;
}
static int
do_decrypt(yki_decrypt_data_t *yki, gpgutil_file_t *in, gpgutil_file_t *out, GError **error)
{
gpgme_error_t gerr;
if ( yki->detached_signature ) {
gerr = gpgme_op_verify(yki->gpgme, in->buffer, out->buffer, NULL);
yki->verify_result = gpgme_op_verify_result(yki->gpgme);
yki->signed_only = TRUE;
}
else {
gerr = gpgme_op_decrypt_verify(yki->gpgme, in->buffer, out->buffer);
yki->decrypt_result = gpgme_op_decrypt_result(yki->gpgme);
yki->verify_result = gpgme_op_verify_result(yki->gpgme);
if ( gpgme_err_code(gerr) == GPG_ERR_NO_DATA ) {
yki->signed_only = TRUE;
gerr = 0;
}
set_default_output(yki);
}
if ( gerr )
yki_error_gpgme(error, YKI_ERROR_GPGME_CRYPTO, gerr);
return gpgme_err_code(gerr) == 0;
}
static int
find_detached_signature_source(const char *sigfile, char **srcfile, GError **error)
{
if ( g_str_has_suffix(sigfile, ".asc") ||
g_str_has_suffix(sigfile, ".gpg") ||
g_str_has_suffix(sigfile, ".sig") )
*srcfile = g_strndup(sigfile, strlen(sigfile) - 4);
if ( ! g_file_test(*srcfile, G_FILE_TEST_EXISTS) ) {
yki_error(error, YKI_ERROR_DETACH_SIG_MISSING_TEXT, "Cannot verify detached signature");
return 0;
}
else
return 1;
}
/* Public interface. */
@ -231,41 +283,38 @@ yki_decrypt(gpgme_ctx_t gpgme, const char *file, GError **error)
ret = gpgutil_open_file(file, "r", &in, error);
if ( ret )
ret = is_file_encrypted(in.buffer, error);
ret = identify_input(&yki, in.buffer, error);
if ( ret )
if ( ret && ! yki.detached_signature )
ret = gpgutil_open_file(NULL, NULL, &out, error);
if ( ret ) {
gpgme_error_t gerr;
if ( ret && yki.detached_signature ) {
char *srcfile;
gerr = gpgme_op_decrypt_verify(gpgme, in.buffer, out.buffer);
yki.decrypt_result = gpgme_op_decrypt_result(gpgme);
yki.verify_result = gpgme_op_verify_result(gpgme);
ret = find_detached_signature_source(file, &srcfile, error);
set_default_output(&yki);
if ( ret )
ret = gpgutil_open_file(srcfile, "r", &out, error);
if ( gpgme_err_code(gerr) == GPG_ERR_NO_DATA ) {
yki.signed_only = TRUE;
gerr = 0;
}
if ( gerr )
yki_error_gpgme(error, YKI_ERROR_GPGME_CRYPTO, gerr);
ret = gpgme_err_code(gerr) == 0;
g_free(srcfile);
}
if ( ret )
ret = do_decrypt(&yki, &in, &out, error);
if ( ret ) {
dlg = create_decrypt_dialog(&yki);
ret = gtk_dialog_run(dlg) == GTK_RESPONSE_OK;
}
if ( ret && g_file_test(yki.output_filename, G_FILE_TEST_EXISTS) && ! yki.output_filename_userset )
ret = yki_confirm_overwrite(yki.output_filename);
if ( ! yki.detached_signature ) {
if ( ret )
ret = gpgutil_copy_buffer(&out, yki.output_filename, error);
if ( ret && g_file_test(yki.output_filename, G_FILE_TEST_EXISTS) && ! yki.output_filename_userset )
ret = yki_confirm_overwrite(yki.output_filename);
if ( ret )
ret = gpgutil_copy_buffer(&out, yki.output_filename, error);
}
gpgutil_close_file(&in, NULL);
gpgutil_close_file(&out, NULL);

1
src/errors.h

@ -9,3 +9,4 @@ DEFINE_YKI_ERROR(7, NOT_IMPLEMENTED, "Feature not implemented")
DEFINE_YKI_ERROR(8, UNKNOWN_DATA, "The file contains unrecognized data")
DEFINE_YKI_ERROR(9, UNENCRYPTED_DATA, "The file is not an encrypted or signed message")
DEFINE_YKI_ERROR(10, IO, "I/O error")
DEFINE_YKI_ERROR(11, DETACH_SIG_MISSING_TEXT, "Missing plaintext for detached signature")

2
src/yki-decrypt.ui

@ -162,7 +162,7 @@
</packing>
</child>
<child>
<object class="GtkFrame" id="frame3">
<object class="GtkFrame" id="frmOutput">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>

Loading…
Cancel
Save