* enable signature verification (WIP)
This commit is contained in:
@ -125,25 +125,6 @@ get_gpg_crypto_context (MuMsgOptions opts, GError **err)
|
|||||||
return cctx;
|
return cctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static GMimeCryptoContext* */
|
|
||||||
/* get_pkcs7_crypto_context (MuMsgOptions opts, GError **err) */
|
|
||||||
/* { */
|
|
||||||
/* GMimeCryptoContext *cctx; */
|
|
||||||
|
|
||||||
/* cctx = g_mime_pkcs7_context_new (password_requester); */
|
|
||||||
/* if (!cctx) { */
|
|
||||||
/* 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(cctx), FALSE); */
|
|
||||||
|
|
||||||
/* return cctx; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static GMimeCryptoContext*
|
static GMimeCryptoContext*
|
||||||
get_crypto_context (MuMsgOptions opts, MuMsgPartPasswordFunc password_func,
|
get_crypto_context (MuMsgOptions opts, MuMsgPartPasswordFunc password_func,
|
||||||
@ -152,14 +133,11 @@ get_crypto_context (MuMsgOptions opts, MuMsgPartPasswordFunc password_func,
|
|||||||
CallbackData *cbdata;
|
CallbackData *cbdata;
|
||||||
GMimeCryptoContext *cctx;
|
GMimeCryptoContext *cctx;
|
||||||
|
|
||||||
/* if (opts & MU_MSG_OPTION_USE_PKCS7) */
|
|
||||||
/* cctx = get_pkcs7_crypto_context (opts, err); */
|
|
||||||
/* else */
|
|
||||||
cctx = get_gpg_crypto_context (opts, err);
|
cctx = get_gpg_crypto_context (opts, err);
|
||||||
|
|
||||||
/* use gobject to pass data to the callback func */
|
/* use gobject to pass data to the callback func */
|
||||||
cbdata = g_new0 (CallbackData, 1);
|
cbdata = g_new0 (CallbackData, 1);
|
||||||
cbdata->pw_func = password_func;
|
cbdata->pw_func = password_func ? password_func : dummy_password_func;
|
||||||
cbdata->user_data = user_data;
|
cbdata->user_data = user_data;
|
||||||
|
|
||||||
g_object_set_data_full (G_OBJECT(cctx), CALLBACK_DATA,
|
g_object_set_data_full (G_OBJECT(cctx), CALLBACK_DATA,
|
||||||
@ -168,239 +146,26 @@ get_crypto_context (MuMsgOptions opts, MuMsgPartPasswordFunc password_func,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static MuMsgPartSigStatus
|
||||||
|
get_verdict (GMimeSignatureList *sigs)
|
||||||
const char*
|
|
||||||
get_pubkey_algo_name (GMimePubKeyAlgo algo)
|
|
||||||
{
|
|
||||||
switch (algo) {
|
|
||||||
case GMIME_PUBKEY_ALGO_DEFAULT:
|
|
||||||
return "default";
|
|
||||||
case GMIME_PUBKEY_ALGO_RSA:
|
|
||||||
return "RSA";
|
|
||||||
case GMIME_PUBKEY_ALGO_RSA_E:
|
|
||||||
return "RSA (encryption only)";
|
|
||||||
case GMIME_PUBKEY_ALGO_RSA_S:
|
|
||||||
return "RSA (signing only)";
|
|
||||||
case GMIME_PUBKEY_ALGO_ELG_E:
|
|
||||||
return "ElGamal (encryption only)";
|
|
||||||
case GMIME_PUBKEY_ALGO_DSA:
|
|
||||||
return "DSA";
|
|
||||||
case GMIME_PUBKEY_ALGO_ELG:
|
|
||||||
return "ElGamal";
|
|
||||||
default:
|
|
||||||
return "unknown algorithm";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const gchar*
|
|
||||||
get_digestkey_algo_name (GMimeDigestAlgo algo)
|
|
||||||
{
|
|
||||||
switch (algo) {
|
|
||||||
case GMIME_DIGEST_ALGO_DEFAULT:
|
|
||||||
return "default";
|
|
||||||
case GMIME_DIGEST_ALGO_MD5:
|
|
||||||
return "MD5";
|
|
||||||
case GMIME_DIGEST_ALGO_SHA1:
|
|
||||||
return "SHA-1";
|
|
||||||
case GMIME_DIGEST_ALGO_RIPEMD160:
|
|
||||||
return "RIPEMD160";
|
|
||||||
case GMIME_DIGEST_ALGO_MD2:
|
|
||||||
return "MD2";
|
|
||||||
case GMIME_DIGEST_ALGO_TIGER192:
|
|
||||||
return "TIGER-192";
|
|
||||||
case GMIME_DIGEST_ALGO_HAVAL5160:
|
|
||||||
return "HAVAL-5-160";
|
|
||||||
case GMIME_DIGEST_ALGO_SHA256:
|
|
||||||
return "SHA-256";
|
|
||||||
case GMIME_DIGEST_ALGO_SHA384:
|
|
||||||
return "SHA-384";
|
|
||||||
case GMIME_DIGEST_ALGO_SHA512:
|
|
||||||
return "SHA-512";
|
|
||||||
case GMIME_DIGEST_ALGO_SHA224:
|
|
||||||
return "SHA-224";
|
|
||||||
case GMIME_DIGEST_ALGO_MD4:
|
|
||||||
return "MD4";
|
|
||||||
default:
|
|
||||||
return "unknown algorithm";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
harvest_certificate_info (GMimeSignature *sig, MuMsgPartSigInfo *siginfo)
|
|
||||||
{
|
|
||||||
GMimeCertificate *cert;
|
|
||||||
|
|
||||||
cert = g_mime_signature_get_certificate (sig);
|
|
||||||
if (!cert)
|
|
||||||
return; /* nothing to harvest */
|
|
||||||
|
|
||||||
siginfo->_cert = cert;
|
|
||||||
|
|
||||||
siginfo->issuer_serial = g_mime_certificate_get_issuer_serial (cert);
|
|
||||||
siginfo->issuer_name = g_mime_certificate_get_issuer_name (cert);
|
|
||||||
siginfo->fingerprint = g_mime_certificate_get_fingerprint (cert);
|
|
||||||
siginfo->key_id = g_mime_certificate_get_key_id (cert);
|
|
||||||
siginfo->email = g_mime_certificate_get_email (cert);
|
|
||||||
siginfo->name = g_mime_certificate_get_name (cert);
|
|
||||||
|
|
||||||
siginfo->pubkey_algo = get_pubkey_algo_name
|
|
||||||
(g_mime_certificate_get_pubkey_algo (cert));
|
|
||||||
siginfo->digest_algo = get_digestkey_algo_name
|
|
||||||
(g_mime_certificate_get_digest_algo (cert));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static MuMsgPartSigInfo*
|
|
||||||
sig_info_new (GMimeSignature *sig)
|
|
||||||
{
|
|
||||||
MuMsgPartSigInfo *siginfo;
|
|
||||||
MuMsgPartSigStatus status;
|
|
||||||
|
|
||||||
switch (g_mime_signature_get_status (sig)) {
|
|
||||||
case GMIME_SIGNATURE_STATUS_GOOD:
|
|
||||||
status = MU_MSG_PART_SIG_STATUS_GOOD; break;
|
|
||||||
case GMIME_SIGNATURE_STATUS_BAD:
|
|
||||||
status = MU_MSG_PART_SIG_STATUS_BAD; break;
|
|
||||||
default:
|
|
||||||
status = MU_MSG_PART_SIG_STATUS_ERROR; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != MU_MSG_PART_SIG_STATUS_GOOD) {
|
|
||||||
GMimeSignatureError sigerr;
|
|
||||||
sigerr = g_mime_signature_get_errors (sig);
|
|
||||||
if (sigerr & GMIME_SIGNATURE_ERROR_EXPSIG)
|
|
||||||
status |= MU_MSG_PART_SIG_STATUS_EXPSIG;
|
|
||||||
if (sigerr & GMIME_SIGNATURE_ERROR_NO_PUBKEY)
|
|
||||||
status |= MU_MSG_PART_SIG_STATUS_NO_PUBKEY;
|
|
||||||
if (sigerr & GMIME_SIGNATURE_ERROR_EXPKEYSIG)
|
|
||||||
status |= MU_MSG_PART_SIG_STATUS_EXPKEYSIG;
|
|
||||||
if (sigerr & GMIME_SIGNATURE_ERROR_REVKEYSIG)
|
|
||||||
status |= MU_MSG_PART_SIG_STATUS_REVKEYSIG;
|
|
||||||
if (sigerr & GMIME_SIGNATURE_ERROR_UNSUPP_ALGO)
|
|
||||||
status |= MU_MSG_PART_SIG_STATUS_UNSUPP_ALGO;
|
|
||||||
}
|
|
||||||
|
|
||||||
siginfo = g_new0 (MuMsgPartSigInfo, 1);
|
|
||||||
siginfo->status = status;
|
|
||||||
siginfo->created = g_mime_signature_get_created (sig);
|
|
||||||
siginfo->expires = g_mime_signature_get_expires (sig);
|
|
||||||
|
|
||||||
harvest_certificate_info (sig, siginfo);
|
|
||||||
|
|
||||||
return siginfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
sig_info_destroy (MuMsgPartSigInfo *siginfo)
|
|
||||||
{
|
|
||||||
if (!siginfo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (G_IS_OBJECT(siginfo->_cert))
|
|
||||||
g_object_unref (siginfo->_cert);
|
|
||||||
|
|
||||||
g_free (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*
|
|
||||||
mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart, MuMsgOptions opts,
|
|
||||||
GError **err)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
GMimeSignatureList *sigs;
|
|
||||||
GMimeCryptoContext *cctx;
|
|
||||||
GSList *siginfos;
|
|
||||||
|
|
||||||
if (!GMIME_IS_MULTIPART_SIGNED (sigmpart)) {
|
|
||||||
mu_util_g_set_error (err, MU_ERROR_IN_PARAMETERS,
|
|
||||||
"not a multipart/signed part");
|
|
||||||
return NULL; /* error */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dummy is good, since we don't need a password when checking
|
|
||||||
* signatures */
|
|
||||||
cctx = get_crypto_context (opts, dummy_password_func, NULL, err);
|
|
||||||
|
|
||||||
if (!cctx) /* return a fake siginfos with the error */
|
|
||||||
return error_sig_infos (); /* error */
|
|
||||||
|
|
||||||
sigs = g_mime_multipart_signed_verify (sigmpart, cctx, err);
|
|
||||||
g_object_unref (cctx);
|
|
||||||
if (!sigs)
|
|
||||||
return NULL; /* error */
|
|
||||||
|
|
||||||
for (i = 0, siginfos = NULL; i != g_mime_signature_list_length (sigs); ++i) {
|
|
||||||
|
|
||||||
MuMsgPartSigInfo *siginfo;
|
|
||||||
siginfo = sig_info_new
|
|
||||||
(g_mime_signature_list_get_signature (sigs, i));
|
|
||||||
|
|
||||||
siginfos = g_slist_prepend (siginfos, siginfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return siginfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
mu_msg_part_free_sig_infos (GSList *siginfos)
|
|
||||||
{
|
|
||||||
g_slist_foreach (siginfos,
|
|
||||||
(GFunc)sig_info_destroy, NULL);
|
|
||||||
g_slist_free (siginfos);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* - if there's any signature with MU_MSG_PART_SIG_STATUS_(ERROR|FAIL),
|
|
||||||
* the verdict is MU_MSG_PART_SIG_STATUS_ERROR
|
|
||||||
* - if not, if there's any signature with MU_MSG_PART_SIG_STATUS_BAD
|
|
||||||
* the verdict is MU_MSG_PART_SIG_STATUS_BAD
|
|
||||||
* - if not, if there's any signature with MU_MSG_PART_SIG_STATUS_GOOD
|
|
||||||
* the verdict is MU_MSG_PART_SIG_STATUS_GOOD
|
|
||||||
* - if not, the verdic is MU_MSG_PART_SIG_STATUS_UNKNOWN
|
|
||||||
*/
|
|
||||||
MuMsgPartSigStatus
|
|
||||||
mu_msg_part_sig_infos_verdict (GSList *sig_infos)
|
|
||||||
{
|
|
||||||
GSList *cur;
|
|
||||||
MuMsgPartSigStatus status;
|
MuMsgPartSigStatus status;
|
||||||
|
|
||||||
status = MU_MSG_PART_SIG_STATUS_UNKNOWN;
|
status = MU_MSG_PART_SIG_STATUS_GOOD; /* let's start positive! */
|
||||||
|
|
||||||
for (cur = sig_infos; cur; cur = g_slist_next (cur)) {
|
for (i = 0; i != g_mime_signature_list_length (sigs); ++i) {
|
||||||
MuMsgPartSigInfo *siginfo;
|
|
||||||
siginfo = (MuMsgPartSigInfo*)cur->data;
|
|
||||||
|
|
||||||
/* if there's an error/failure, the verdict is error */
|
GMimeSignature *msig;
|
||||||
if (siginfo->status & MU_MSG_PART_SIG_STATUS_ERROR ||
|
GMimeSignatureStatus sigstat;
|
||||||
siginfo->status & MU_MSG_PART_SIG_STATUS_FAIL)
|
msig = g_mime_signature_list_get_signature (sigs, i);
|
||||||
return MU_MSG_PART_SIG_STATUS_ERROR;
|
sigstat = g_mime_signature_get_status (msig);
|
||||||
|
|
||||||
if (siginfo->status & MU_MSG_PART_SIG_STATUS_BAD)
|
switch (sigstat) {
|
||||||
status = MU_MSG_PART_SIG_STATUS_BAD;
|
case GMIME_SIGNATURE_STATUS_GOOD: continue;
|
||||||
|
case GMIME_SIGNATURE_STATUS_ERROR: return MU_MSG_PART_SIG_STATUS_ERROR;
|
||||||
if ((siginfo->status & MU_MSG_PART_SIG_STATUS_GOOD) &&
|
case GMIME_SIGNATURE_STATUS_BAD: return MU_MSG_PART_SIG_STATUS_BAD;
|
||||||
status == MU_MSG_PART_SIG_STATUS_UNKNOWN)
|
}
|
||||||
status = MU_MSG_PART_SIG_STATUS_GOOD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -408,122 +173,41 @@ mu_msg_part_sig_infos_verdict (GSList *sig_infos)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MuMsgPartSigStatus
|
||||||
const char*
|
mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, MuMsgOptions opts,
|
||||||
mu_msg_part_sig_status_to_string (MuMsgPartSigStatus status)
|
GError **err)
|
||||||
{
|
{
|
||||||
switch (status) {
|
MuMsgPartSigStatus sigstat;
|
||||||
case MU_MSG_PART_SIG_STATUS_UNKNOWN:
|
GMimeCryptoContext *ctx;
|
||||||
return "no signed part found";
|
GMimeSignatureList *sigs;
|
||||||
case MU_MSG_PART_SIG_STATUS_GOOD:
|
|
||||||
return "good";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_BAD:
|
|
||||||
return "bad signature";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_ERROR:
|
|
||||||
return "error verifying signature";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_FAIL:
|
|
||||||
return "crypto failed";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_EXPSIG:
|
|
||||||
return "signature is expired";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_NO_PUBKEY:
|
|
||||||
return "no public key found";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_EXPKEYSIG:
|
|
||||||
return "expired public key";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_REVKEYSIG:
|
|
||||||
return "revoked public key";
|
|
||||||
case MU_MSG_PART_SIG_STATUS_UNSUPP_ALGO:
|
|
||||||
return "unsupported algorithm";
|
|
||||||
default:
|
|
||||||
g_warning ("%s: invalid status %d",
|
|
||||||
__FUNCTION__, status);
|
|
||||||
return "invalid status";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
g_return_val_if_fail (GMIME_IS_MULTIPART_SIGNED(sig),
|
||||||
|
MU_MSG_PART_SIG_STATUS_FAIL);
|
||||||
|
|
||||||
char*
|
ctx = get_crypto_context (opts, NULL, NULL, err);
|
||||||
mu_msg_part_sig_statuses_to_string (MuMsgPartSigStatus status)
|
if (!ctx) {
|
||||||
{
|
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
|
||||||
unsigned u;
|
"failed to get crypto context");
|
||||||
GString *gstr;
|
return MU_MSG_PART_SIG_STATUS_FAIL;
|
||||||
|
|
||||||
MuMsgPartSigStatus statuses[] = {
|
|
||||||
MU_MSG_PART_SIG_STATUS_UNKNOWN,
|
|
||||||
MU_MSG_PART_SIG_STATUS_GOOD,
|
|
||||||
MU_MSG_PART_SIG_STATUS_BAD,
|
|
||||||
MU_MSG_PART_SIG_STATUS_ERROR,
|
|
||||||
MU_MSG_PART_SIG_STATUS_FAIL,
|
|
||||||
MU_MSG_PART_SIG_STATUS_EXPSIG,
|
|
||||||
MU_MSG_PART_SIG_STATUS_NO_PUBKEY,
|
|
||||||
MU_MSG_PART_SIG_STATUS_EXPKEYSIG,
|
|
||||||
MU_MSG_PART_SIG_STATUS_REVKEYSIG,
|
|
||||||
MU_MSG_PART_SIG_STATUS_UNSUPP_ALGO
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (u = 0; u != G_N_ELEMENTS(statuses); ++u) {
|
|
||||||
const gchar *statstr;
|
|
||||||
if (!(status & statuses[u]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
statstr = mu_msg_part_sig_status_to_string (statuses[u]);
|
|
||||||
if (gstr->len != 0)
|
|
||||||
gstr = g_string_append (gstr, ", ");
|
|
||||||
|
|
||||||
gstr = g_string_append (gstr, statstr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return g_string_free (gstr, FALSE);
|
sigs = g_mime_multipart_signed_verify (sig, ctx, err);
|
||||||
|
g_object_unref (ctx);
|
||||||
|
if (!sigs) {
|
||||||
|
if (err && !*err)
|
||||||
|
mu_util_g_set_error (err, MU_ERROR_CRYPTO,
|
||||||
|
"verification failed");
|
||||||
|
return MU_MSG_PART_SIG_STATUS_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sigstat = get_verdict (sigs);
|
||||||
|
g_mime_signature_list_clear (sigs);
|
||||||
|
|
||||||
|
return sigstat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
g_string_append_printf (gstr, "; algorithms (P/D) (%s, %s)",
|
|
||||||
info->pubkey_algo, info->digest_algo);
|
|
||||||
|
|
||||||
g_string_append_printf (gstr, "; created: %s, expires: %s",
|
|
||||||
mu_date_str_s ("%c", info->created),
|
|
||||||
mu_date_str_s ("%c", info->expires));
|
|
||||||
|
|
||||||
if (info->name || info->email)
|
|
||||||
g_string_append_printf (gstr, "; who:%s %s",
|
|
||||||
info->name ? info-> name : "",
|
|
||||||
info->email ? info->email : "");
|
|
||||||
|
|
||||||
if (info->issuer_name && info->issuer_serial)
|
|
||||||
g_string_append_printf (gstr, "; issuer: %s (%s)",
|
|
||||||
info->issuer_name,
|
|
||||||
info->issuer_serial);
|
|
||||||
if (info->fingerprint)
|
|
||||||
g_string_append_printf (gstr, "; fingerprint: %s",
|
|
||||||
info->fingerprint);
|
|
||||||
|
|
||||||
return g_string_free (gstr, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GMimeObject* /* this is declared in mu-msg-priv.h */
|
GMimeObject* /* this is declared in mu-msg-priv.h */
|
||||||
mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts,
|
mu_msg_crypto_decrypt_part (GMimeMultipartEncrypted *enc, MuMsgOptions opts,
|
||||||
|
|||||||
@ -25,104 +25,6 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <mu-msg.h>
|
#include <mu-msg.h>
|
||||||
|
|
||||||
/* the signature status */
|
|
||||||
enum _MuMsgPartSigStatus {
|
|
||||||
MU_MSG_PART_SIG_STATUS_UNKNOWN = 0,
|
|
||||||
MU_MSG_PART_SIG_STATUS_GOOD = 1 << 0,
|
|
||||||
|
|
||||||
MU_MSG_PART_SIG_STATUS_BAD = 1 << 1,
|
|
||||||
MU_MSG_PART_SIG_STATUS_ERROR = 1 << 2,
|
|
||||||
|
|
||||||
/* status when crypto does not work */
|
|
||||||
MU_MSG_PART_SIG_STATUS_FAIL = 1 << 3,
|
|
||||||
|
|
||||||
MU_MSG_PART_SIG_STATUS_EXPSIG = 1 << 4, /* expired sig */
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
struct _MuMsgPartSigInfo {
|
|
||||||
time_t created; /* creation time */
|
|
||||||
time_t expires; /* expiration time */
|
|
||||||
MuMsgPartSigStatus status; /* status of the signature */
|
|
||||||
|
|
||||||
const char *issuer_serial; /* issuer's serial #*/
|
|
||||||
const char *issuer_name; /* issuer name */
|
|
||||||
const char *fingerprint; /* fingerprint */
|
|
||||||
const char *key_id; /* key id */
|
|
||||||
const char *email;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
const char *pubkey_algo; /* public key algorithm */
|
|
||||||
const char *digest_algo; /* digest algorithm */
|
|
||||||
|
|
||||||
const char *errmsg; /* errmsg when status ==
|
|
||||||
* MU_MSG_PART_SIG_STATUS_FAIL */
|
|
||||||
/* don't touch */
|
|
||||||
gpointer _cert;
|
|
||||||
};
|
|
||||||
typedef struct _MuMsgPartSigInfo MuMsgPartSigInfo;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get a human-readable string describing @param status; note, status
|
|
||||||
* must match a _single_ status.
|
|
||||||
*
|
|
||||||
* @param status
|
|
||||||
*
|
|
||||||
* @return a constant string describing status
|
|
||||||
*/
|
|
||||||
const char* mu_msg_part_sig_status_to_string (MuMsgPartSigStatus status);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* summarize the signature checks to one status:
|
|
||||||
*
|
|
||||||
* - if there's any signature with MU_MSG_PART_SIG_STATUS_(ERROR|FAIL),
|
|
||||||
* the verdict is MU_MSG_PART_SIG_STATUS_ERROR
|
|
||||||
* - if not, if there's any signature with MU_MSG_PART_SIG_STATUS_BAD
|
|
||||||
* the verdict is MU_MSG_PART_SIG_STATUS_BAD
|
|
||||||
* - if not, if there's any signature with MU_MSG_PART_SIG_STATUS_GOOD
|
|
||||||
* the verdict is MU_MSG_PART_SIG_STATUS_GOOD
|
|
||||||
* - if not, the verdic is MU_MSG_PART_SIG_STATUS_UNKNOWN
|
|
||||||
*
|
|
||||||
* @param sig_infos
|
|
||||||
*
|
|
||||||
* @return the status
|
|
||||||
*/
|
|
||||||
MuMsgPartSigStatus mu_msg_part_sig_infos_verdict (GSList *sig_infos);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* @param info a MuMsgPartSigInfo ptr
|
|
||||||
*
|
|
||||||
* @return a newly allocated string (g_free)
|
|
||||||
*/
|
|
||||||
char* mu_msg_part_sig_info_to_string (MuMsgPartSigInfo *info)
|
|
||||||
G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* free the list of MuMsgPartSigInfo structures
|
|
||||||
*
|
|
||||||
* @param siginfo
|
|
||||||
*/
|
|
||||||
void mu_msg_part_free_sig_infos (GSList *siginfos);
|
|
||||||
|
|
||||||
struct _MuMsgDecryptedPart;
|
struct _MuMsgDecryptedPart;
|
||||||
typedef struct _MuMsgDecryptedPart MuMsgDecryptedPart;
|
typedef struct _MuMsgDecryptedPart MuMsgDecryptedPart;
|
||||||
|
|||||||
@ -220,87 +220,6 @@ get_part_size (GMimePart *part)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* #ifdef BUILD_CRYPTO */
|
|
||||||
/* static void */
|
|
||||||
/* check_signature_maybe (GMimeObject *parent, GMimeObject *mobj, MuMsgPart *pi, */
|
|
||||||
/* MuMsgOptions opts) */
|
|
||||||
/* { */
|
|
||||||
/* GMimeContentType *ctype; */
|
|
||||||
/* GError *err; */
|
|
||||||
/* gboolean pkcs7; */
|
|
||||||
|
|
||||||
/* if (!GMIME_IS_MULTIPART_SIGNED (parent)) */
|
|
||||||
/* return; */
|
|
||||||
|
|
||||||
/* ctype = g_mime_object_get_content_type (mobj); */
|
|
||||||
/* if (g_mime_content_type_is_type */
|
|
||||||
/* (ctype, "application", "pgp-signature")) */
|
|
||||||
/* pkcs7 = FALSE; */
|
|
||||||
/* else if (g_mime_content_type_is_type */
|
|
||||||
/* (ctype, "application", "x-pkcs7-signature")) */
|
|
||||||
/* pkcs7 = TRUE; */
|
|
||||||
/* else return; /\* don't know how to handle other kinds *\/ */
|
|
||||||
|
|
||||||
/* if (pkcs7) */
|
|
||||||
/* opts |= MU_MSG_OPTION_USE_PKCS7; /\* gpg is the default *\/ */
|
|
||||||
|
|
||||||
/* err = NULL; */
|
|
||||||
/* pi->sig_infos = mu_msg_mime_sig_infos */
|
|
||||||
/* (GMIME_MULTIPART_SIGNED (parent), opts, &err); */
|
|
||||||
/* if (err) { */
|
|
||||||
/* g_warning ("error verifying signature: %s", err->message); */
|
|
||||||
/* g_clear_error (&err); */
|
|
||||||
/* } */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* #endif /\*BUILD_CRYPTO*\/ */
|
|
||||||
|
|
||||||
/* static gboolean */
|
|
||||||
/* init_msg_part_from_mime_part (MuMsgOptions opts, GMimeObject *parent, */
|
|
||||||
/* GMimePart *part, MuMsgPart *pi) */
|
|
||||||
/* { */
|
|
||||||
/* const gchar *fname, *descr; */
|
|
||||||
/* GMimeContentType *ct; */
|
|
||||||
|
|
||||||
/* ct = g_mime_object_get_content_type ((GMimeObject*)part); */
|
|
||||||
/* if (GMIME_IS_CONTENT_TYPE(ct)) { */
|
|
||||||
/* pi->type = (char*)g_mime_content_type_get_media_type (ct); */
|
|
||||||
/* pi->subtype = (char*)g_mime_content_type_get_media_subtype (ct); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* pi->disposition = (char*)g_mime_object_get_disposition */
|
|
||||||
/* ((GMimeObject*)part); */
|
|
||||||
|
|
||||||
/* fname = g_mime_part_get_filename (part); */
|
|
||||||
/* pi->file_name = fname ? mu_str_utf8ify (fname) : NULL; */
|
|
||||||
|
|
||||||
/* descr = g_mime_part_get_content_description (part); */
|
|
||||||
/* pi->description = descr ? mu_str_utf8ify (descr) : NULL; */
|
|
||||||
/* pi->size = get_part_size (part); */
|
|
||||||
/* pi->part_type = MU_MSG_PART_TYPE_LEAF; */
|
|
||||||
|
|
||||||
/* if (!pi->disposition || */
|
|
||||||
/* g_ascii_strcasecmp (pi->disposition, */
|
|
||||||
/* GMIME_DISPOSITION_INLINE) == 0) */
|
|
||||||
/* pi->part_type |= MU_MSG_PART_TYPE_INLINE; */
|
|
||||||
|
|
||||||
/* if (GMIME_IS_MULTIPART_SIGNED (parent)) */
|
|
||||||
/* pi->part_type |= MU_MSG_PART_TYPE_SIGNED; */
|
|
||||||
|
|
||||||
/* /\* if we have crypto support, check the signature if there is one *\/ */
|
|
||||||
/* #ifdef BUILD_CRYPTO */
|
|
||||||
/* if (opts & MU_MSG_OPTION_CHECK_SIGNATURES) */
|
|
||||||
/* check_signature_maybe (parent, (GMimeObject*)part, */
|
|
||||||
/* pi, opts); */
|
|
||||||
/* #endif /\*BUILD_CRYPTO*\/ */
|
|
||||||
|
|
||||||
/* return TRUE; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cleanup_filename (char *fname)
|
cleanup_filename (char *fname)
|
||||||
{
|
{
|
||||||
@ -378,13 +297,28 @@ get_disposition (GMimeObject *mobj)
|
|||||||
return MU_MSG_PART_TYPE_NONE;
|
return MU_MSG_PART_TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SIG_STATUS "sig-status"
|
||||||
|
|
||||||
/* call 'func' with information about this MIME-part */
|
/* call 'func' with information about this MIME-part */
|
||||||
static gboolean
|
static gboolean
|
||||||
handle_signed_part (MuMsg *msg,
|
check_signature (MuMsg *msg, GMimeMultipartSigned *part, MuMsgOptions opts)
|
||||||
GMimeMultipartSigned *part, GMimeObject *parent,
|
|
||||||
MuMsgOptions opts, unsigned index,
|
|
||||||
MuMsgPartForeachFunc func, gpointer user_data)
|
|
||||||
{
|
{
|
||||||
|
/* the signature status */
|
||||||
|
MuMsgPartSigStatus sigstat;
|
||||||
|
GError *err;
|
||||||
|
|
||||||
|
err = NULL;
|
||||||
|
sigstat = mu_msg_crypto_verify_part (part, opts, &err);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
g_warning ("error verifying signature: %s", err->message);
|
||||||
|
g_clear_error (&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag this part with the signature status check */
|
||||||
|
g_object_set_data (G_OBJECT(part), SIG_STATUS,
|
||||||
|
GSIZE_TO_POINTER(sigstat));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,6 +348,12 @@ handle_part (MuMsg *msg, GMimePart *part, GMimeObject *parent,
|
|||||||
msgpart.part_type = MU_MSG_PART_TYPE_LEAF;
|
msgpart.part_type = MU_MSG_PART_TYPE_LEAF;
|
||||||
msgpart.part_type |= get_disposition ((GMimeObject*)part);
|
msgpart.part_type |= get_disposition ((GMimeObject*)part);
|
||||||
|
|
||||||
|
/* get the sig status from the parent */
|
||||||
|
msgpart.sig_status =
|
||||||
|
(MuMsgPartSigStatus)
|
||||||
|
GPOINTER_TO_SIZE(g_object_get_data (G_OBJECT(parent),
|
||||||
|
SIG_STATUS));
|
||||||
|
|
||||||
ct = g_mime_object_get_content_type ((GMimeObject*)part);
|
ct = g_mime_object_get_content_type ((GMimeObject*)part);
|
||||||
if (GMIME_IS_CONTENT_TYPE(ct)) {
|
if (GMIME_IS_CONTENT_TYPE(ct)) {
|
||||||
msgpart.type = g_mime_content_type_get_media_type (ct);
|
msgpart.type = g_mime_content_type_get_media_type (ct);
|
||||||
@ -480,9 +420,8 @@ handle_mime_object (MuMsg *msg,
|
|||||||
(msg, GMIME_MESSAGE_PART(mobj),
|
(msg, GMIME_MESSAGE_PART(mobj),
|
||||||
parent, opts, index, func, user_data);
|
parent, opts, index, func, user_data);
|
||||||
else if (GMIME_IS_MULTIPART_SIGNED (mobj))
|
else if (GMIME_IS_MULTIPART_SIGNED (mobj))
|
||||||
return handle_signed_part
|
return check_signature
|
||||||
(msg, GMIME_MULTIPART_SIGNED (mobj),
|
(msg, GMIME_MULTIPART_SIGNED (mobj), opts);
|
||||||
parent, opts, index, func, user_data);
|
|
||||||
else if (GMIME_IS_MULTIPART_ENCRYPTED (mobj))
|
else if (GMIME_IS_MULTIPART_ENCRYPTED (mobj))
|
||||||
return handle_encrypted_part
|
return handle_encrypted_part
|
||||||
(msg, GMIME_MULTIPART_ENCRYPTED (mobj),
|
(msg, GMIME_MULTIPART_ENCRYPTED (mobj),
|
||||||
|
|||||||
@ -52,6 +52,18 @@ enum _MuMsgPartType {
|
|||||||
typedef enum _MuMsgPartType MuMsgPartType;
|
typedef enum _MuMsgPartType MuMsgPartType;
|
||||||
|
|
||||||
|
|
||||||
|
/* the signature status */
|
||||||
|
enum _MuMsgPartSigStatus {
|
||||||
|
MU_MSG_PART_SIG_STATUS_UNSIGNED = 0,
|
||||||
|
|
||||||
|
MU_MSG_PART_SIG_STATUS_GOOD,
|
||||||
|
MU_MSG_PART_SIG_STATUS_BAD,
|
||||||
|
MU_MSG_PART_SIG_STATUS_ERROR,
|
||||||
|
MU_MSG_PART_SIG_STATUS_FAIL
|
||||||
|
};
|
||||||
|
typedef enum _MuMsgPartSigStatus MuMsgPartSigStatus;
|
||||||
|
|
||||||
|
|
||||||
struct _MuMsgPart {
|
struct _MuMsgPart {
|
||||||
|
|
||||||
/* index of this message part */
|
/* index of this message part */
|
||||||
@ -69,10 +81,9 @@ struct _MuMsgPart {
|
|||||||
|
|
||||||
gpointer data; /* opaque data */
|
gpointer data; /* opaque data */
|
||||||
|
|
||||||
MuMsgPartType part_type;
|
MuMsgPartType part_type;
|
||||||
|
MuMsgPartSigStatus sig_status;
|
||||||
|
|
||||||
/* crypto stuff */
|
|
||||||
GSList *sig_infos; /* list of MuMsgPartSig */
|
|
||||||
};
|
};
|
||||||
typedef struct _MuMsgPart MuMsgPart;
|
typedef struct _MuMsgPart MuMsgPart;
|
||||||
|
|
||||||
|
|||||||
@ -108,19 +108,6 @@ void mu_mime_message_foreach (GMimeMessage *msg, gboolean decrypt,
|
|||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
#ifdef BUILD_CRYPTO
|
#ifdef BUILD_CRYPTO
|
||||||
/**
|
|
||||||
* get signature information for the mime part
|
|
||||||
*
|
|
||||||
* @param part a multipart/sigde part
|
|
||||||
* @param opts options for the signature verification (we only use the
|
|
||||||
* crypto-related options in opts)
|
|
||||||
* @param err receives error info
|
|
||||||
*
|
|
||||||
* @return a list of MuMsgPartSig, or NULL
|
|
||||||
*/
|
|
||||||
GSList* mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart,
|
|
||||||
MuMsgOptions opts, GError **err);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* callback function to retrieve a password from the user
|
* callback function to retrieve a password from the user
|
||||||
*
|
*
|
||||||
@ -134,6 +121,21 @@ GSList* mu_msg_mime_sig_infos (GMimeMultipartSigned *sigmpart,
|
|||||||
typedef char* (*MuMsgPartPasswordFunc) (const char *user_id, const char *prompt_ctx,
|
typedef char* (*MuMsgPartPasswordFunc) (const char *user_id, const char *prompt_ctx,
|
||||||
gboolean reprompt, gpointer user_data);
|
gboolean reprompt, gpointer user_data);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* verify the signature of a signed message part
|
||||||
|
*
|
||||||
|
* @param sig a signed message part
|
||||||
|
* @param opts message options
|
||||||
|
* @param err receive error information
|
||||||
|
*
|
||||||
|
* @return the verification status, or MU_MSG_PART_SIG_STATUS_FAIL in
|
||||||
|
* case of some internal error
|
||||||
|
*/
|
||||||
|
MuMsgPartSigStatus mu_msg_crypto_verify_part (GMimeMultipartSigned *sig, MuMsgOptions opts,
|
||||||
|
GError **err);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decrypt the given encrypted mime multipart
|
* decrypt the given encrypted mime multipart
|
||||||
*
|
*
|
||||||
|
|||||||
@ -263,10 +263,12 @@ elvis (const char *s1, const char *s2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
sig_verdict (GSList *sig_infos)
|
sig_verdict (MuMsgPart *mpart)
|
||||||
{
|
{
|
||||||
#ifdef BUILD_CRYPTO
|
#ifdef BUILD_CRYPTO
|
||||||
switch (mu_msg_part_sig_infos_verdict (sig_infos)) {
|
MuMsgPartSigStatus sigstat;
|
||||||
|
|
||||||
|
switch (mpart->sig_status) {
|
||||||
case MU_MSG_PART_SIG_STATUS_GOOD:
|
case MU_MSG_PART_SIG_STATUS_GOOD:
|
||||||
return ":signature good";
|
return ":signature good";
|
||||||
case MU_MSG_PART_SIG_STATUS_BAD:
|
case MU_MSG_PART_SIG_STATUS_BAD:
|
||||||
@ -338,7 +340,7 @@ each_part (MuMsg *msg, MuMsgPart *part, PartInfo *pinfo)
|
|||||||
parttype,
|
parttype,
|
||||||
mu_msg_part_maybe_attachment (part) ? "t" : "nil",
|
mu_msg_part_maybe_attachment (part) ? "t" : "nil",
|
||||||
(int)part->size,
|
(int)part->size,
|
||||||
sig_verdict (part->sig_infos));
|
sig_verdict (part));
|
||||||
|
|
||||||
g_free (pinfo->parts);
|
g_free (pinfo->parts);
|
||||||
pinfo->parts = tmp;
|
pinfo->parts = tmp;
|
||||||
|
|||||||
78
mu/mu-cmd.c
78
mu/mu-cmd.c
@ -401,40 +401,14 @@ mu_cmd_remove (MuStore *store, MuConfig *opts, GError **err)
|
|||||||
|
|
||||||
|
|
||||||
#ifdef BUILD_CRYPTO
|
#ifdef BUILD_CRYPTO
|
||||||
struct _VData {
|
static void
|
||||||
MuMsgPartSigStatus status;
|
each_sig (MuMsg *msg, MuMsgPart *part, MuMsgPartSigStatus *sigstat)
|
||||||
MuConfig*opts;
|
|
||||||
gchar *msg;
|
|
||||||
};
|
|
||||||
typedef struct _VData VData;
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
each_sig (MuMsg *msg, MuMsgPart *part, VData *vdata)
|
|
||||||
{
|
{
|
||||||
GSList *cur;
|
if (*sigstat == MU_MSG_PART_SIG_STATUS_BAD ||
|
||||||
|
*sigstat == MU_MSG_PART_SIG_STATUS_ERROR)
|
||||||
if (!part->sig_infos)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (vdata->opts->verbose)
|
*sigstat = part->sig_status;
|
||||||
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)) {
|
|
||||||
|
|
||||||
MuMsgPartSigInfo *sig_info;
|
|
||||||
sig_info = (MuMsgPartSigInfo*)cur->data;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MuError
|
MuError
|
||||||
@ -442,7 +416,7 @@ mu_cmd_verify (MuConfig *opts, GError **err)
|
|||||||
{
|
{
|
||||||
MuMsg *msg;
|
MuMsg *msg;
|
||||||
MuMsgOptions msgopts;
|
MuMsgOptions msgopts;
|
||||||
VData vdata;
|
MuMsgPartSigStatus sigstat;
|
||||||
|
|
||||||
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,
|
||||||
@ -454,34 +428,40 @@ mu_cmd_verify (MuConfig *opts, GError **err)
|
|||||||
|
|
||||||
msgopts = mu_config_get_msg_options (opts);
|
msgopts = mu_config_get_msg_options (opts);
|
||||||
|
|
||||||
vdata.status = MU_MSG_PART_SIG_STATUS_UNKNOWN;
|
sigstat = MU_MSG_PART_SIG_STATUS_UNSIGNED;
|
||||||
vdata.opts = opts;
|
mu_msg_part_foreach (msg, msgopts,
|
||||||
vdata.msg = NULL;
|
(MuMsgPartForeachFunc)each_sig, &sigstat);
|
||||||
|
|
||||||
/* TODO: update for decryption */
|
|
||||||
mu_msg_part_foreach (msg, msgopts, (MuMsgPartForeachFunc)each_sig, &vdata);
|
|
||||||
|
|
||||||
/* 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) {
|
if (!opts->quiet) {
|
||||||
gchar *str;
|
const char *verdict;
|
||||||
str = mu_msg_part_sig_statuses_to_string (vdata.status);
|
|
||||||
g_print ("verdict: %s\n", str);
|
switch (sigstat) {
|
||||||
g_free (str);
|
case MU_MSG_PART_SIG_STATUS_UNSIGNED:
|
||||||
|
verdict = "no signature found"; break;
|
||||||
|
case MU_MSG_PART_SIG_STATUS_GOOD:
|
||||||
|
verdict = "signature verified"; break;
|
||||||
|
case MU_MSG_PART_SIG_STATUS_BAD:
|
||||||
|
verdict = "signature not verified"; break;
|
||||||
|
case MU_MSG_PART_SIG_STATUS_ERROR:
|
||||||
|
verdict = "failed to verify signature"; break;
|
||||||
|
case MU_MSG_PART_SIG_STATUS_FAIL:
|
||||||
|
verdict = "error in verification process"; break;
|
||||||
|
default:
|
||||||
|
g_return_val_if_reached (MU_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("verdict: %s\n", verdict);
|
||||||
}
|
}
|
||||||
|
|
||||||
mu_msg_unref (msg);
|
mu_msg_unref (msg);
|
||||||
|
|
||||||
return vdata.status == MU_MSG_PART_SIG_STATUS_GOOD ? MU_OK : MU_ERROR;
|
return sigstat == MU_MSG_PART_SIG_STATUS_GOOD ? MU_OK : MU_ERROR;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
MuError
|
MuError
|
||||||
mu_cmd_verify (MuConfig *opts, GError **err)
|
mu_cmd_verify (MuConfig *opts, GError **err)
|
||||||
{
|
{
|
||||||
g_warning ("your version of mu does not support the 'verify' command");
|
g_warning ("this version of mu does not support the 'verify' command");
|
||||||
return MU_ERROR_IN_PARAMETERS;
|
return MU_ERROR_IN_PARAMETERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user