NULL
};
-static char *create_boundary (void);
+static char *create_boundary (void);
+
+static void sig_expiration_check (GString *str,
+ GpgmeCtx ctx,
+ GpgmeKey key,
+ GpgmeSigStat status,
+ int idx);
+static void sig_expired (GString *str,
+ GpgmeCtx ctx,
+ int idx);
+static void sig_key_expired (GString *str,
+ GpgmeKey key,
+ int idx);
#if 0
static void dump_mimeinfo (const char *text, MimeInfo *x)
case GPGME_SIG_STAT_GOOD:
result = _("Good signature");
break;
+ case GPGME_SIG_STAT_GOOD_EXP:
+ result = _("Good signature but it has expired");
+ break;
+ case GPGME_SIG_STAT_GOOD_EXPKEY:
+ result = _("Good signature but the key has expired");
+ break;
case GPGME_SIG_STAT_BAD:
result = _("BAD signature");
break;
case GPGME_SIG_STAT_GOOD:
result = _("Good signature from \"%s\"");
break;
+ case GPGME_SIG_STAT_GOOD_EXP:
+ result = _("Good signature from \"%s\" but it has expired");
+ break;
+ case GPGME_SIG_STAT_GOOD_EXPKEY:
+ result = _("Good signature from \"%s\" but the key has expired");
+ break;
case GPGME_SIG_STAT_BAD:
- result = _("BAD signature from \"%s\"");
+ result = _("BAD signature from \"%s\"");
break;
case GPGME_SIG_STAT_NOKEY:
result = _("No public key to verify the signature");
if ((fpr != NULL) && (*fpr != '\0'))
g_string_sprintfa (str, "Key fingerprint: %s\n", fpr);
g_string_append (str, _("Cannot find user ID for this key."));
+ sig_expiration_check(str, ctx, key, status, 0);
return;
}
g_string_sprintfa (str, sig_status_with_name (status), uid);
g_string_sprintfa (str, _(" aka \"%s\"\n"),
uid);
}
+ sig_expiration_check(str, ctx, key, status, 0);
+}
+
+static void
+sig_expiration_check(GString *str, GpgmeCtx ctx, GpgmeKey key,
+ GpgmeSigStat status, int idx)
+{
+ if (status == GPGME_SIG_STAT_GOOD_EXP)
+ sig_expired(str, ctx, idx);
+ else if (status == GPGME_SIG_STAT_GOOD_EXPKEY)
+ sig_key_expired(str, key, idx);
+}
+
+static void
+sig_expired(GString *str, GpgmeCtx ctx, int idx)
+{
+ unsigned long exp_time;
+ exp_time = gpgme_get_sig_ulong_attr(ctx, idx, GPGME_ATTR_EXPIRE, 0);
+ g_string_sprintfa(str, _("Signature expired %s"), ctime(&exp_time));
+}
+
+static void
+sig_key_expired(GString *str, GpgmeKey key, int idx)
+{
+ unsigned long exp_time;
+ exp_time = gpgme_key_get_ulong_attr(key, GPGME_ATTR_EXPIRE, NULL, idx);
+ g_string_sprintfa(str, _("Key expired %s"), ctime(&exp_time));
}
static gchar *
strftime (ctime_str, sizeof (ctime_str), "%c",
ctime_val);
g_string_sprintfa (str,
- _("Signature made %s\n"),
+ _("Signature made at %s\n"),
ctime_str);
}
err = gpgme_get_sig_key (ctx, sig_idx, &key);
GpgmeSigStat status = GPGME_SIG_STAT_NONE;
GpgmegtkSigStatus statuswindow = NULL;
const char *result = NULL;
+ gchar *tmp_file;
+ gint n_exclude_chars = 0;
if (prefs_common.gpg_signature_popup)
statuswindow = gpgmegtk_sig_status_create ();
goto leave;
}
- /* don't include the last character (LF). It does not belong to the
- * signed text */
- err = gpgme_data_new_from_filepart (&text, NULL, fp,
- mimeinfo->children->fpos,
- mimeinfo->children->size ?
- (mimeinfo->children->size - 1) : 0 );
+ /* don't include the last empty line.
+ It does not belong to the signed text */
+ if (mimeinfo->children->size > 0) {
+ if (fseek(fp, mimeinfo->children->fpos + mimeinfo->children->size - 1,
+ SEEK_SET) < 0) {
+ perror("fseek");
+ goto leave;
+ }
+ if (fgetc(fp) == '\n') {
+ n_exclude_chars++;
+ if (mimeinfo->children->size > 1) {
+ if (fseek(fp, mimeinfo->children->fpos + mimeinfo->children->size - 2,
+ SEEK_SET) < 0) {
+ perror("fseek");
+ goto leave;
+ }
+ if (fgetc(fp) == '\r')
+ n_exclude_chars++;
+ }
+ }
+ }
+
+ /* canonicalize the file part. */
+ tmp_file = get_tmp_file();
+ if (copy_file_part(fp, mimeinfo->children->fpos,
+ mimeinfo->children->size - n_exclude_chars,
+ tmp_file) < 0) {
+ g_free(tmp_file);
+ goto leave;
+ }
+ if (canonicalize_file_replace(tmp_file) < 0) {
+ unlink(tmp_file);
+ g_free(tmp_file);
+ goto leave;
+ }
+
+ err = gpgme_data_new_from_file(&text, tmp_file, 1);
+
+ unlink(tmp_file);
+ g_free(tmp_file);
+
if (!err)
err = gpgme_data_new_from_filepart (&sig, NULL, fp,
partinfo->fpos, partinfo->size);
}
err = gpgme_op_verify (ctx, sig, text, &status);
- if (err)
+ if (err) {
debug_print ("gpgme_op_verify failed: %s\n", gpgme_strerror (err));
+ goto leave;
+ }
/* FIXME: check what the heck this sig_status_full stuff is.
* it should better go into sigstatus.c */
result = gpgmegtk_sig_status_to_string(status);
debug_print("verification status: %s\n", result);
if (prefs_common.gpg_signature_popup)
- gpgmegtk_sig_status_update (statuswindow,ctx);
+ gpgmegtk_sig_status_update (statuswindow, ctx);
- g_assert (!err); /* FIXME: Hey: this may indeed happen */
g_free (partinfo->sigstatus);
partinfo->sigstatus = g_strdup (result);
+ partinfo->sig_ok = (status == GPGME_SIG_STAT_GOOD);
+ partinfo->sig_unknown = (status == GPGME_SIG_STAT_NOKEY);
+ partinfo->sig_expired = (status == GPGME_SIG_STAT_GOOD_EXP);
+ partinfo->key_expired = (status == GPGME_SIG_STAT_GOOD_EXPKEY);
gpgme_data_release (sig);
gpgme_data_release (text);
int rfc2015_is_encrypted (MimeInfo *mimeinfo)
{
- if (!mimeinfo)
+ if (!mimeinfo || mimeinfo->mime_type != MIME_MULTIPART)
return 0;
if (g_strcasecmp (mimeinfo->content_type, "multipart/encrypted"))
return 0;
return 1;
}
-gboolean rfc2015_msg_is_encrypted (gchar *file)
+gboolean rfc2015_msg_is_encrypted (const gchar *file)
{
FILE *fp;
MimeInfo *mimeinfo;
if (ascii_armored) {
fprintf(fp,
- "Content-Type: text/plain; charset=us-ascii\r\n"
+ "Content-Type: text/plain; charset=US-ASCII\r\n"
"Content-Transfer-Encoding: 7bit\r\n"
"\r\n");
} else {
/* and the final boundary */
if (!ascii_armored) {
fprintf (fp,
- "\r\n"
- "--%s--\r\n"
- "\r\n",
- boundary);
+ "\r\n"
+ "--%s--\r\n",
+ boundary);
}
fflush (fp);
if (ferror (fp)) {
* r_siginfo returns an XML object with information about the signature.
*/
static GpgmeData
-pgp_sign (GpgmeData plain, GSList *key_list, char **r_siginfo)
+pgp_sign (GpgmeData plain, GSList *key_list, gboolean clearsign,
+ char **r_siginfo)
{
GSList *p;
GpgmeCtx ctx = NULL;
if (err)
goto leave;
- err = gpgme_op_sign (ctx, plain, sig, GPGME_SIG_MODE_DETACH);
+ err = gpgme_op_sign
+ (ctx, plain, sig,
+ clearsign ? GPGME_SIG_MODE_CLEAR : GPGME_SIG_MODE_DETACH);
if (!err)
*r_siginfo = gpgme_get_op_info (ctx, 0);
goto failure;
}
- sigdata = pgp_sign (plain, key_list, &siginfo);
+ sigdata = pgp_sign (plain, key_list, FALSE, &siginfo);
if (siginfo) {
micalg = extract_micalg (siginfo);
free (siginfo);
header = NULL;
if (!mime_version_seen)
- fputs ("MIME-Version: 1\r\n", fp);
+ fputs ("MIME-Version: 1.0\r\n", fp);
fprintf (fp, "Content-Type: multipart/signed; "
"protocol=\"application/pgp-signature\";\r\n");
if (micalg)
- fprintf (fp, " micalg=%s;", micalg );
- fprintf (fp, " boundary=\"%s\"\r\n", boundary );
+ fprintf (fp, " micalg=\"%s\";", micalg);
+ fprintf (fp, " boundary=\"%s\"\r\n", boundary);
/* Part 1: signed material */
- fprintf (fp, "\r\n--%s\r\n", boundary);
+ fprintf (fp, "\r\n"
+ "--%s\r\n",
+ boundary);
err = gpgme_data_rewind (plain);
if (err) {
debug_print ("gpgme_data_rewind on plain failed: %s\n",
}
/* Part 2: signature */
- fprintf (fp, "\r\n--%s\r\n", boundary);
+ fprintf (fp, "\r\n"
+ "--%s\r\n",
+ boundary);
fputs ("Content-Type: application/pgp-signature\r\n"
"\r\n", fp);
}
/* Final boundary */
- fprintf (fp, "\r\n--%s--\r\n\r\n", boundary);
+ fprintf (fp, "\r\n"
+ "--%s--\r\n",
+ boundary);
fflush (fp);
if (ferror (fp)) {
FILE_OP_ERROR (file, "fwrite");
}
+/*
+ * Sign the file with clear text and replace its content with the signed one.
+ */
+gint
+rfc2015_clearsign (const gchar *file, GSList *key_list)
+{
+ FILE *fp;
+ gchar buf[BUFFSIZE];
+ GpgmeError err;
+ GpgmeData text = NULL;
+ GpgmeData sigdata = NULL;
+ size_t nread;
+ gchar *siginfo;
+
+ if ((fp = fopen(file, "rb")) == NULL) {
+ FILE_OP_ERROR(file, "fopen");
+ goto failure;
+ }
+
+ err = gpgme_data_new(&text);
+ if (err) {
+ debug_print("gpgme_data_new failed: %s\n", gpgme_strerror(err));
+ goto failure;
+ }
+
+ while (!err && fgets(buf, sizeof(buf), fp)) {
+ err = gpgme_data_write(text, buf, strlen(buf));
+ }
+ if (ferror(fp)) {
+ FILE_OP_ERROR(file, "fgets");
+ goto failure;
+ }
+ if (err) {
+ debug_print("gpgme_data_write failed: %s\n", gpgme_strerror(err));
+ goto failure;
+ }
+
+ sigdata = pgp_sign(text, key_list, TRUE, &siginfo);
+ if (siginfo) {
+ g_free(siginfo);
+ }
+ if (!sigdata)
+ goto failure;
+
+ if (fclose(fp) == EOF) {
+ FILE_OP_ERROR(file, "fclose");
+ fp = NULL;
+ goto failure;
+ }
+ if ((fp = fopen(file, "wb")) == NULL) {
+ FILE_OP_ERROR(file, "fopen");
+ goto failure;
+ }
+
+ err = gpgme_data_rewind(sigdata);
+ if (err) {
+ debug_print("gpgme_data_rewind on sigdata failed: %s\n",
+ gpgme_strerror(err));
+ goto failure;
+ }
+
+ while (!(err = gpgme_data_read(sigdata, buf, sizeof(buf), &nread))) {
+ fwrite(buf, nread, 1, fp);
+ }
+ if (err != GPGME_EOF) {
+ debug_print("gpgme_data_read failed: %s\n", gpgme_strerror(err));
+ goto failure;
+ }
+
+ if (fclose(fp) == EOF) {
+ FILE_OP_ERROR(file, "fclose");
+ fp = NULL;
+ goto failure;
+ }
+ gpgme_data_release(text);
+ gpgme_data_release(sigdata);
+ return 0;
+
+failure:
+ if (fp)
+ fclose(fp);
+ gpgme_data_release(text);
+ gpgme_data_release(sigdata);
+ return -1;
+}
+
+
/****************
* Create a new boundary in a way that it is very unlikely that this
* will occur in the following text. It would be easy to ensure