* crypto: better handling of crypto errors

This commit is contained in:
djcb
2012-07-18 10:30:23 +03:00
parent d50fa234a1
commit 807c9de625
5 changed files with 165 additions and 43 deletions

View File

@ -43,7 +43,7 @@ dummy_password_requester (GMimeCryptoContext *ctx, const char *user_id,
GMimeCryptoContext* GMimeCryptoContext*
get_crypto_context (MuMsgPartOptions opts, GError **err) get_gpg_crypto_context (MuMsgPartOptions opts, GError **err)
{ {
GMimeCryptoContext *ctx; GMimeCryptoContext *ctx;
const char *prog; const char *prog;
@ -64,9 +64,9 @@ get_crypto_context (MuMsgPartOptions opts, GError **err)
path); path);
g_free (path); g_free (path);
} }
if (!ctx) { if (!ctx) {
mu_util_g_set_error (err, MU_ERROR, "failed to get crypto context"); mu_util_g_set_error (err, MU_ERROR,
"failed to get GPG crypto context");
return NULL; return NULL;
} }
@ -74,15 +74,38 @@ get_crypto_context (MuMsgPartOptions opts, GError **err)
(GMIME_GPG_CONTEXT(ctx), (GMIME_GPG_CONTEXT(ctx),
opts & MU_MSG_PART_OPTION_USE_AGENT); opts & MU_MSG_PART_OPTION_USE_AGENT);
g_mime_gpg_context_set_always_trust g_mime_gpg_context_set_always_trust
(GMIME_GPG_CONTEXT(ctx), FALSE); (GMIME_GPG_CONTEXT(ctx),
opts & MU_MSG_PART_OPTION_TRUST_ALWAYS);
g_mime_gpg_context_set_auto_key_retrieve g_mime_gpg_context_set_auto_key_retrieve
(GMIME_GPG_CONTEXT(ctx), (GMIME_GPG_CONTEXT(ctx),
opts & MU_MSG_PART_OPTION_AUTO_RETRIEVE_KEY); opts & MU_MSG_PART_OPTION_AUTO_RETRIEVE_KEY);
return ctx; return ctx;
} }
GMimeCryptoContext*
get_pkcs7_crypto_context (MuMsgPartOptions opts, GError **err)
{
GMimeCryptoContext *ctx;
ctx = g_mime_pkcs7_context_new
((GMimePasswordRequestFunc)dummy_password_requester);
if (!ctx) {
mu_util_g_set_error (err, MU_ERROR,
"failed to get PKCS7 crypto context");
return NULL;
}
g_mime_pkcs7_context_set_always_trust
(GMIME_PKCS7_CONTEXT(ctx),
opts & MU_MSG_PART_OPTION_TRUST_ALWAYS);
return ctx;
}
const char* const char*
get_pubkey_algo_name (GMimePubKeyAlgo algo) get_pubkey_algo_name (GMimePubKeyAlgo algo)
{ {
@ -216,6 +239,19 @@ sig_info_destroy (MuMsgPartSigInfo *siginfo)
} }
/* we create a fake siginfo when things go wrong */
static GSList*
error_sig_infos (void)
{
MuMsgPartSigInfo *sig_info;
sig_info = g_new0 (MuMsgPartSigInfo, 1);
sig_info->status = MU_MSG_PART_SIG_STATUS_FAIL;
return g_slist_prepend (NULL, sig_info);
}
GSList* GSList*
mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart, MuMsgPartOptions opts, mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart, MuMsgPartOptions opts,
@ -223,7 +259,7 @@ mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart, MuMsgPartOptions opts,
{ {
int i; int i;
GMimeSignatureList *sigs; GMimeSignatureList *sigs;
GMimeCryptoContext *gpgctx; GMimeCryptoContext *cctx;
GSList *siginfos; GSList *siginfos;
if (!GMIME_IS_MULTIPART_SIGNED (sigmpart)) { if (!GMIME_IS_MULTIPART_SIGNED (sigmpart)) {
@ -232,20 +268,23 @@ mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart, MuMsgPartOptions opts,
return NULL; /* error */ return NULL; /* error */
} }
gpgctx = get_crypto_context (opts, err); if (opts & MU_MSG_PART_OPTION_USE_PKCS7)
if (!gpgctx) cctx = get_pkcs7_crypto_context (opts, err);
return NULL; /* error */ else
cctx = get_gpg_crypto_context (opts, err);
sigs = g_mime_multipart_signed_verify (sigmpart, gpgctx, err); /* return a fake siginfos with the error */
g_object_unref (gpgctx); if (!cctx)
return error_sig_infos (); /* error */
sigs = g_mime_multipart_signed_verify (sigmpart, cctx, err);
g_object_unref (cctx);
if (!sigs) if (!sigs)
return NULL; /* error */ return NULL; /* error */
for (i = 0, siginfos = NULL; i != g_mime_signature_list_length (sigs); ++i) { for (i = 0, siginfos = NULL; i != g_mime_signature_list_length (sigs); ++i) {
MuMsgPartSigInfo *siginfo; MuMsgPartSigInfo *siginfo;
siginfo = sig_info_new siginfo = sig_info_new
(g_mime_signature_list_get_signature (sigs, i)); (g_mime_signature_list_get_signature (sigs, i));
@ -270,13 +309,15 @@ mu_msg_part_sig_status_to_string (MuMsgPartSigStatus status)
{ {
switch (status) { switch (status) {
case MU_MSG_PART_SIG_STATUS_UNKNOWN: case MU_MSG_PART_SIG_STATUS_UNKNOWN:
return "unknown"; return "no signed part found";
case MU_MSG_PART_SIG_STATUS_GOOD: case MU_MSG_PART_SIG_STATUS_GOOD:
return "good"; return "good";
case MU_MSG_PART_SIG_STATUS_BAD: case MU_MSG_PART_SIG_STATUS_BAD:
return "bad signature"; return "bad signature";
case MU_MSG_PART_SIG_STATUS_ERROR: case MU_MSG_PART_SIG_STATUS_ERROR:
return "error verifying signature"; return "error verifying signature";
case MU_MSG_PART_SIG_STATUS_FAIL:
return "crypto failed";
case MU_MSG_PART_SIG_STATUS_EXPSIG: case MU_MSG_PART_SIG_STATUS_EXPSIG:
return "signature is expired"; return "signature is expired";
case MU_MSG_PART_SIG_STATUS_NO_PUBKEY: case MU_MSG_PART_SIG_STATUS_NO_PUBKEY:
@ -296,7 +337,7 @@ mu_msg_part_sig_status_to_string (MuMsgPartSigStatus status)
char* char*
mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info) mu_msg_part_sig_statuses_to_string (MuMsgPartSigStatus status)
{ {
unsigned u; unsigned u;
GString *gstr; GString *gstr;
@ -306,6 +347,7 @@ mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info)
MU_MSG_PART_SIG_STATUS_GOOD, MU_MSG_PART_SIG_STATUS_GOOD,
MU_MSG_PART_SIG_STATUS_BAD, MU_MSG_PART_SIG_STATUS_BAD,
MU_MSG_PART_SIG_STATUS_ERROR, MU_MSG_PART_SIG_STATUS_ERROR,
MU_MSG_PART_SIG_STATUS_FAIL,
MU_MSG_PART_SIG_STATUS_EXPSIG, MU_MSG_PART_SIG_STATUS_EXPSIG,
MU_MSG_PART_SIG_STATUS_NO_PUBKEY, MU_MSG_PART_SIG_STATUS_NO_PUBKEY,
MU_MSG_PART_SIG_STATUS_EXPKEYSIG, MU_MSG_PART_SIG_STATUS_EXPKEYSIG,
@ -313,14 +355,15 @@ mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info)
MU_MSG_PART_SIG_STATUS_UNSUPP_ALGO MU_MSG_PART_SIG_STATUS_UNSUPP_ALGO
}; };
g_return_val_if_fail (info, NULL); if (status == MU_MSG_PART_SIG_STATUS_UNKNOWN)
return g_strdup
(mu_msg_part_sig_status_to_string (status));
gstr = g_string_sized_new (128); gstr = g_string_sized_new (128);
for (u = 0; u != G_N_ELEMENTS(statuses); ++u) { for (u = 0; u != G_N_ELEMENTS(statuses); ++u) {
const gchar *statstr; const gchar *statstr;
if (!(status & statuses[u]))
if (!(info->status & statuses[u]))
continue; continue;
statstr = mu_msg_part_sig_status_to_string (statuses[u]); statstr = mu_msg_part_sig_status_to_string (statuses[u]);
@ -330,9 +373,27 @@ mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info)
gstr = g_string_append (gstr, statstr); gstr = g_string_append (gstr, statstr);
} }
gstr = g_string_prepend (gstr, "status: "); return g_string_free (gstr, FALSE);
}
if (info->status & MU_MSG_PART_SIG_STATUS_ERROR)
char*
mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info)
{
GString *gstr;
gchar *statuses;
g_return_val_if_fail (info, NULL);
gstr = g_string_sized_new (128);
statuses = mu_msg_part_sig_statuses_to_string (info->status);
g_string_append_printf (gstr, "status: %s", statuses);
g_free (statuses);
if (info->status & MU_MSG_PART_SIG_STATUS_ERROR ||
info->status & MU_MSG_PART_SIG_STATUS_FAIL)
return g_string_free (gstr, FALSE); return g_string_free (gstr, FALSE);
g_string_append_printf (gstr, "; algorithms (P/D) (%s, %s)", g_string_append_printf (gstr, "; algorithms (P/D) (%s, %s)",

View File

@ -33,11 +33,14 @@ enum _MuMsgPartSigStatus {
MU_MSG_PART_SIG_STATUS_BAD = 1 << 1, MU_MSG_PART_SIG_STATUS_BAD = 1 << 1,
MU_MSG_PART_SIG_STATUS_ERROR = 1 << 2, MU_MSG_PART_SIG_STATUS_ERROR = 1 << 2,
MU_MSG_PART_SIG_STATUS_EXPSIG = 1 << 3, /* expired sig */ /* status when crypto does not work */
MU_MSG_PART_SIG_STATUS_NO_PUBKEY = 1 << 4, /* no public key */ MU_MSG_PART_SIG_STATUS_FAIL = 1 << 3,
MU_MSG_PART_SIG_STATUS_EXPKEYSIG = 1 << 5, /* key expired */
MU_MSG_PART_SIG_STATUS_REVKEYSIG = 1 << 6, /* revoked key */ MU_MSG_PART_SIG_STATUS_EXPSIG = 1 << 4, /* expired sig */
MU_MSG_PART_SIG_STATUS_UNSUPP_ALGO = 1 << 7 /* unsupp'd algo */ MU_MSG_PART_SIG_STATUS_NO_PUBKEY = 1 << 5, /* no public key */
MU_MSG_PART_SIG_STATUS_EXPKEYSIG = 1 << 6, /* key expired */
MU_MSG_PART_SIG_STATUS_REVKEYSIG = 1 << 7, /* revoked key */
MU_MSG_PART_SIG_STATUS_UNSUPP_ALGO = 1 << 8 /* unsupp'd algo */
}; };
typedef enum _MuMsgPartSigStatus MuMsgPartSigStatus; typedef enum _MuMsgPartSigStatus MuMsgPartSigStatus;
@ -57,6 +60,8 @@ struct _MuMsgPartSigInfo {
const char *pubkey_algo; /* public key algorithm */ const char *pubkey_algo; /* public key algorithm */
const char *digest_algo; /* digest algorithm */ const char *digest_algo; /* digest algorithm */
const char *errmsg; /* errmsg when status ==
* MU_MSG_PART_SIG_STATUS_FAIL */
/* don't touch */ /* don't touch */
gpointer _cert; gpointer _cert;
}; };
@ -74,6 +79,17 @@ typedef struct _MuMsgPartSigInfo MuMsgPartSigInfo;
const char* mu_msg_part_sig_status_to_string (MuMsgPartSigStatus status); const char* mu_msg_part_sig_status_to_string (MuMsgPartSigStatus status);
/**
* convert the bitwise-OR'ed statuses to a string
*
* @param statuses bitwise-OR'ed statuses
*
* @return newly allocated string (g_free)
*/
char* mu_msg_part_sig_statuses_to_string (MuMsgPartSigStatus statuses)
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
/** /**
* get a human readable-description of siginfo * get a human readable-description of siginfo
* *
@ -81,7 +97,8 @@ const char* mu_msg_part_sig_status_to_string (MuMsgPartSigStatus status);
* *
* @return a newly allocated string (g_free) * @return a newly allocated string (g_free)
*/ */
char* mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info); char* mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info)
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
/** /**
* free the list of MuMsgPartSigInfo structures * free the list of MuMsgPartSigInfo structures

View File

@ -248,19 +248,27 @@ check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi,
MuMsgPartOptions opts) MuMsgPartOptions opts)
{ {
#ifdef BUILD_CRYPTO #ifdef BUILD_CRYPTO
GMimeContentType *ctype;
GError *err; GError *err;
err = NULL; gboolean pkcs7;
if (!GMIME_IS_MULTIPART_SIGNED (parent)) if (!GMIME_IS_MULTIPART_SIGNED (parent))
return; return;
/* we're interested in the signed thing here, not the ctype = g_mime_object_get_content_type (mobj);
* signature itself */ if (g_mime_content_type_is_type
if (g_mime_content_type_is_type ( (ctype, "application", "pgp-signature"))
g_mime_object_get_content_type (mobj), pkcs7 = FALSE;
"application", "pgp-signature")) else if (g_mime_content_type_is_type
return; (ctype, "application", "x-pkcs7-signature"))
pkcs7 = TRUE;
else return; /* don't know how to handle other kinds */
if (pkcs7)
opts |= MU_MSG_PART_OPTION_USE_PKCS7; /* gpg is the default */
err = NULL;
pi->sig_infos = mu_msg_mime_sig_infos pi->sig_infos = mu_msg_mime_sig_infos
(GMIME_MULTIPART_SIGNED (parent), opts, &err); (GMIME_MULTIPART_SIGNED (parent), opts, &err);
if (err) { if (err) {

View File

@ -219,7 +219,9 @@ enum _MuMsgPartOptions {
* if mu was built with crypto support */ * if mu was built with crypto support */
MU_MSG_PART_OPTION_CHECK_SIGNATURES = 1 << 1, MU_MSG_PART_OPTION_CHECK_SIGNATURES = 1 << 1,
MU_MSG_PART_OPTION_AUTO_RETRIEVE_KEY = 1 << 2, MU_MSG_PART_OPTION_AUTO_RETRIEVE_KEY = 1 << 2,
MU_MSG_PART_OPTION_USE_AGENT = 1 << 3 MU_MSG_PART_OPTION_USE_AGENT = 1 << 3,
MU_MSG_PART_OPTION_TRUST_ALWAYS = 1 << 4,
MU_MSG_PART_OPTION_USE_PKCS7 = 1 << 5 /* gpg is the default */
}; };
typedef enum _MuMsgPartOptions MuMsgPartOptions; typedef enum _MuMsgPartOptions MuMsgPartOptions;

View File

@ -397,22 +397,39 @@ mu_cmd_remove (MuStore *store, MuConfig *opts, GError **err)
#ifdef BUILD_CRYPTO #ifdef BUILD_CRYPTO
static void print_signatures (MuMsg *msg, MuMsgPart *part, MuConfig *opts) struct _VData {
MuMsgPartSigStatus status;
MuConfig*opts;
gchar *msg;
};
typedef struct _VData VData;
static void
each_sig (MuMsg *msg, MuMsgPart *part, VData *vdata)
{ {
GSList *cur; GSList *cur;
if (!part->sig_infos) if (!part->sig_infos)
return; return;
g_print ("MIME-part %u has %u signature(s): ", if (vdata->opts->verbose)
part->index, g_slist_length (part->sig_infos)); g_print ("MIME-part %u has %u signature(s): ",
part->index, g_slist_length (part->sig_infos));
for (cur = part->sig_infos; cur; cur = g_slist_next (cur)) { for (cur = part->sig_infos; cur; cur = g_slist_next (cur)) {
char *descr;
descr = mu_msg_part_sig_info_to_string MuMsgPartSigInfo *sig_info;
((MuMsgPartSigInfo*)cur->data); sig_info = (MuMsgPartSigInfo*)cur->data;
g_print ("%s\n", descr);
g_free (descr); if (vdata->opts->verbose) {
char *descr;
descr = mu_msg_part_sig_info_to_string (sig_info);
g_print ("%s\n", descr);
g_free (descr);
}
vdata->status |= sig_info->status;
} }
} }
@ -421,6 +438,7 @@ mu_cmd_verify (MuConfig *opts, GError **err)
{ {
MuMsg *msg; MuMsg *msg;
MuMsgPartOptions partopts; MuMsgPartOptions partopts;
VData vdata;
g_return_val_if_fail (opts, MU_ERROR_INTERNAL); g_return_val_if_fail (opts, MU_ERROR_INTERNAL);
g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_VERIFY, g_return_val_if_fail (opts->cmd == MU_CONFIG_CMD_VERIFY,
@ -436,12 +454,28 @@ mu_cmd_verify (MuConfig *opts, GError **err)
if (opts->use_agent) if (opts->use_agent)
partopts |= MU_MSG_PART_OPTION_USE_AGENT; partopts |= MU_MSG_PART_OPTION_USE_AGENT;
mu_msg_part_foreach (msg,(MuMsgPartForeachFunc)print_signatures, opts, vdata.status = MU_MSG_PART_SIG_STATUS_UNKNOWN;
vdata.opts = opts;
vdata.msg = NULL;
mu_msg_part_foreach (msg,(MuMsgPartForeachFunc)each_sig, &vdata,
partopts); partopts);
/* if there's anything bad, all goodness goes away */
if (vdata.status & MU_MSG_PART_SIG_STATUS_BAD ||
vdata.status & MU_MSG_PART_SIG_STATUS_ERROR)
vdata.status &= ~MU_MSG_PART_SIG_STATUS_GOOD;
if (!opts->quiet) {
gchar *str;
str = mu_msg_part_sig_statuses_to_string (vdata.status);
g_print ("verdict: %s\n", str);
g_free (str);
}
mu_msg_unref (msg); mu_msg_unref (msg);
return MU_OK; return vdata.status == MU_MSG_PART_SIG_STATUS_GOOD ? MU_OK : MU_ERROR;
} }
#else #else
MuError MuError