📄 crypt-gpgme.c
字号:
"has expired\n"), s); } if ((sum & GPGME_SIGSUM_SIG_EXPIRED)) { gpgme_verify_result_t result; gpgme_signature_t sig; unsigned int i; result = gpgme_op_verify_result (ctx); for (sig = result->signatures, i = 0; sig && (i < idx); sig = sig->next, i++) ; state_attach_puts (_("Warning: The signature expired at: "), s); print_time (sig ? sig->exp_timestamp : 0, s); state_attach_puts ("\n", s); } if ((sum & GPGME_SIGSUM_KEY_MISSING)) state_attach_puts (_("Can't verify due to a missing " "key or certificate\n"), s); if ((sum & GPGME_SIGSUM_CRL_MISSING)) { state_attach_puts (_("The CRL is not available\n"), s); severe = 1; } if ((sum & GPGME_SIGSUM_CRL_TOO_OLD)) { state_attach_puts (_("Available CRL is too old\n"), s); severe = 1; } if ((sum & GPGME_SIGSUM_BAD_POLICY)) state_attach_puts (_("A policy requirement was not met\n"), s); if ((sum & GPGME_SIGSUM_SYS_ERROR)) { const char *t0 = NULL, *t1 = NULL; gpgme_verify_result_t result; gpgme_signature_t sig; unsigned int i; state_attach_puts (_("A system error occurred"), s ); /* Try to figure out some more detailed system error information. */ result = gpgme_op_verify_result (ctx); for (sig = result->signatures, i = 0; sig && (i < idx); sig = sig->next, i++) ; if (sig) { t0 = ""; t1 = sig->wrong_key_usage ? "Wrong_Key_Usage" : ""; } if (t0 || t1) { state_attach_puts (": ", s); if (t0) state_attach_puts (t0, s); if (t1 && !(t0 && !strcmp (t0, t1))) { if (t0) state_attach_puts (",", s); state_attach_puts (t1, s); } } state_attach_puts ("\n", s); } return severe;}static void show_fingerprint (gpgme_key_t key, STATE *state){ const char *s; int i, is_pgp; char *buf, *p; const char *prefix = _("Fingerprint: "); if (!key) return; s = key->subkeys ? key->subkeys->fpr : NULL; if (!s) return; is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP); buf = safe_malloc ( strlen (prefix) + strlen(s) * 4 + 2 ); strcpy (buf, prefix); /* __STRCPY_CHECKED__ */ p = buf + strlen (buf); if (is_pgp && strlen (s) == 40) { /* PGP v4 style formatted. */ for (i=0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++) { *p++ = s[0]; *p++ = s[1]; *p++ = s[2]; *p++ = s[3]; *p++ = ' '; if (i == 4) *p++ = ' '; } } else { for (i=0; *s && s[1] && s[2]; s += 2, i++) { *p++ = s[0]; *p++ = s[1]; *p++ = is_pgp? ' ':':'; if (is_pgp && i == 7) *p++ = ' '; } } /* just in case print remaining odd digits */ for (; *s; s++) *p++ = *s; *p++ = '\n'; *p = 0; state_attach_puts (buf, state); FREE (&buf);}/* Show the valididy of a key used for one signature. */static void show_one_sig_validity (gpgme_ctx_t ctx, int idx, STATE *s){ gpgme_verify_result_t result = NULL; gpgme_signature_t sig = NULL; const char *txt = NULL; result = gpgme_op_verify_result (ctx); if (result) for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--); switch (sig ? sig->validity : 0) { case GPGME_VALIDITY_UNKNOWN: txt = _("WARNING: We have NO indication whether " "the key belongs to the person named " "as shown above\n"); break; case GPGME_VALIDITY_UNDEFINED: break; case GPGME_VALIDITY_NEVER: txt = _("WARNING: The key does NOT BELONG to " "the person named as shown above\n"); break; case GPGME_VALIDITY_MARGINAL: txt = _("WARNING: It is NOT certain that the key " "belongs to the person named as shown above\n"); break; case GPGME_VALIDITY_FULL: case GPGME_VALIDITY_ULTIMATE: txt = NULL; break; } if (txt) state_attach_puts (txt, s);}/* Show information about one signature. This fucntion is called with the context CTX of a sucessful verification operation and the enumerator IDX which should start at 0 and incremete for each call/signature. Return values are: 0 for normal procession, 1 for a bad signature, 2 for a signature with a warning or -1 for no more signature. */static int show_one_sig_status (gpgme_ctx_t ctx, int idx, STATE *s){ time_t created; const char *fpr, *uid; gpgme_key_t key = NULL; int i, anybad = 0, anywarn = 0; unsigned int sum; gpgme_user_id_t uids = NULL; gpgme_verify_result_t result; gpgme_signature_t sig; gpgme_error_t err = GPG_ERR_NO_ERROR; result = gpgme_op_verify_result (ctx); if (result) { /* FIXME: this code should use a static variable and remember the current position in the list of signatures, IMHO. -moritz. */ for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next) ; if (! sig) return -1; /* Signature not found. */ if (signature_key) { gpgme_key_release (signature_key); signature_key = NULL; } created = sig->timestamp; fpr = sig->fpr; sum = sig->summary; if (gpg_err_code (sig->status) != GPG_ERR_NO_ERROR) anybad = 1; err = gpgme_get_key (ctx, fpr, &key, 0); /* secret key? */ if (! err) { uid = (key->uids && key->uids->uid) ? key->uids->uid : "[?]"; if (! signature_key) signature_key = key; } else { key = NULL; /* Old gpgme versions did not set KEY to NULL on error. Do it here to avoid a double free. */ uid = "[?]"; } if (!s || !s->fpout || !(s->flags & M_DISPLAY)) ; /* No state information so no way to print anything. */ else if (err) { state_attach_puts (_("Error getting key information: "), s); state_attach_puts ( gpg_strerror (err), s ); state_attach_puts ("\n", s); anybad = 1; } else if ((sum & GPGME_SIGSUM_GREEN)) { state_attach_puts (_("Good signature from: "), s); state_attach_puts (uid, s); state_attach_puts ("\n", s); for (i = 1, uids = key->uids; uids; i++, uids = uids->next) { if (i == 1) /* Skip primary UID. */ continue; if (uids->revoked) continue; state_attach_puts (_(" aka: "), s); state_attach_puts (uids->uid, s); state_attach_puts ("\n", s); } state_attach_puts (_(" created: "), s); print_time (created, s); state_attach_puts ("\n", s); if (show_sig_summary (sum, ctx, key, idx, s)) anywarn = 1; show_one_sig_validity (ctx, idx, s); } else if ((sum & GPGME_SIGSUM_RED)) { state_attach_puts (_("*BAD* signature claimed to be from: "), s); state_attach_puts (uid, s); state_attach_puts ("\n", s); show_sig_summary (sum, ctx, key, idx, s); } else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP)) { /* We can't decide (yellow) but this is a PGP key with a good signature, so we display what a PGP user expects: The name, fingerprint and the key validity (which is neither fully or ultimate). */ state_attach_puts (_("Good signature from: "), s); state_attach_puts (uid, s); state_attach_puts ("\n", s); state_attach_puts (_(" created: "), s); print_time (created, s); state_attach_puts ("\n", s); show_one_sig_validity (ctx, idx, s); show_fingerprint (key,s); if (show_sig_summary (sum, ctx, key, idx, s)) anywarn = 1; } else /* can't decide (yellow) */ { state_attach_puts (_("Error checking signature"), s); state_attach_puts ("\n", s); show_sig_summary (sum, ctx, key, idx, s); } if (key != signature_key) gpgme_key_release (key); } return anybad ? 1 : anywarn ? 2 : 0;}/* Do the actual verification step. With IS_SMIME set to true we assume S/MIME (surprise!) */static int verify_one (BODY *sigbdy, STATE *s, const char *tempfile, int is_smime){ int badsig = -1; int anywarn = 0; int err; gpgme_ctx_t ctx; gpgme_data_t signature, message; signature = file_to_data_object (s->fpin, sigbdy->offset, sigbdy->length); if (!signature) return -1; /* We need to tell gpgme about the encoding because the backend can't auto-detect plain base-64 encoding which is used by S/MIME. */ if (is_smime) gpgme_data_set_encoding (signature, GPGME_DATA_ENCODING_BASE64); err = gpgme_data_new_from_file (&message, tempfile, 1); if (err) { gpgme_data_release (signature); mutt_error (_("error allocating data object: %s\n"), gpgme_strerror (err)); return -1; } ctx = create_gpgme_context (is_smime); /* Note: We don't need a current time output because GPGME avoids such an attack by separating the meta information from the data. */ state_attach_puts (_("[-- Begin signature information --]\n"), s); err = gpgme_op_verify (ctx, signature, message, NULL); mutt_need_hard_redraw (); if (err) { char buf[200]; snprintf (buf, sizeof(buf)-1, _("Error: verification failed: %s\n"), gpgme_strerror (err)); state_attach_puts (buf, s); } else { /* Verification succeeded, see what the result is. */ int res, idx; int anybad = 0; if (signature_key) { gpgme_key_release (signature_key); signature_key = NULL; } for(idx=0; (res = show_one_sig_status (ctx, idx, s)) != -1; idx++) { if (res == 1) anybad = 1; else if (res == 2) anywarn = 2; } if (!anybad) badsig = 0; } if (!badsig) { gpgme_verify_result_t result; gpgme_sig_notation_t notation; gpgme_signature_t signature; result = gpgme_op_verify_result (ctx); if (result) { for (signature = result->signatures; signature; signature = signature->next) { if (signature->notations) { char buf[SHORT_STRING]; snprintf (buf, sizeof (buf), _("*** Begin Notation (signature by: %s) ***\n"), signature->fpr); state_attach_puts (buf, s); for (notation = signature->notations; notation; notation = notation->next) { if (notation->name) { state_attach_puts (notation->name, s); state_attach_puts ("=", s); } if (notation->value) { state_attach_puts (notation->value, s); if (!(*notation->value && (notation->value[strlen (notation->value)-1]=='\n'))) state_attach_puts ("\n", s); } } state_attach_puts (_("*** End Notation ***\n"), s); } } } } gpgme_release (ctx); state_attach_puts (_("[-- End signature information --]\n\n"), s); dprint (1, (debugfile, "verify_one: returning %d.\n", badsig)); return badsig? 1: anywarn? 2 : 0;}int pgp_gpgme_verify_one (BODY *sigbdy, STATE *s, const char *tempfile){ return verify_one (sigbdy, s, tempfile, 0);}int smime_gpgme_verify_one (BODY *sigbdy, STATE *s, const char *tempfile){ return verify_one (sigbdy, s, tempfile, 1);}/* * Implementation of `decrypt_part'. *//* Decrypt a PGP or SMIME message (depending on the boolean flag IS_SMIME) with body A described further by state S. Write plaintext out to file FPOUT and return a new body. For PGP returns a flag in R_IS_SIGNED to indicate whether this is a combined encrypted and signed message, for S/MIME it returns true when it is not a encrypted but a signed message. */static BODY *decrypt_part (BODY *a, STATE *s, FILE *fpout, int is_smime, int *r_is_signed){ struct stat info; BODY *tattach; int err; gpgme_ctx_t ctx; gpgme_data_t ciphertext, plaintext; int maybe_signed = 0; int anywarn = 0; int sig_stat = 0; if (r_is_signed) *r_is_signed = 0; ctx = create_gpgme_context (is_smime); restart: /* Make a data object from the body, create context etc. */ ciphertext = file_to_data_object (s->fpin, a->offset, a->length); if (!ciphertext) return NULL; plaintext = create_gpgme_data (); /* Do the decryption or the verification in case of the S/MIME hack. */ if ((! is_smime) || maybe_signed) { if (! is_smime) err = gpgme_op_decrypt_verify (ctx, ciphertext, plaintext); else if (maybe_signed) err = gpgme_op_verify (ctx, ciphertext, NULL, plaintext); { /* Check wether signatures have been verified. */ gpgme_verify_result_t verify_result = gpgme_op_verify_result (ctx); if (verify_result->signatures) sig_stat = 1; } } else err = gpgme_op_decrypt (ctx, ciphertext, plaintext); gpgme_data_release (ciphertext); if (err) { if (is_smime && !maybe_signed && gpg_err_code (err) == GPG_ERR_NO_DATA) { /* Check whether this might be a signed message despite what the mime header told us. Retry then. gpgsm returns the error information "unsupported Algorithm '?'" but gpgme will not store this unknown algorithm, thus we test that it has not been set. */ gpgme_decrypt_result_t result; result = gpgme_op_decrypt_result (ctx); if (!result->unsupported_algorithm) { maybe_signed = 1; gpgme_data_release (plaintext); goto restart; } } mutt_need_hard_redraw (); if ((s->flags & M_DISPLAY)) { char buf[200]; snprintf (buf, sizeof(buf)-1, _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror (err)); state_attach_puts (buf, s); } gpgme_data_release (plaintext); gpgme_release (ctx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -