📄 crypt-gpgme.c
字号:
mutt_mktemp (tempfile); fp = safe_fopen (tempfile, "w+"); if (!fp) { mutt_perror (tempfile); return NULL; } err = ((gpgme_data_seek (data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno (errno) : 0); if (!err) { char buf[4096]; while ((nread = gpgme_data_read (data, buf, sizeof (buf)))) { if (fwrite (buf, nread, 1, fp) != 1) { mutt_perror (tempfile); fclose (fp); unlink (tempfile); return NULL; } } } if (ret_fp) rewind (fp); else fclose (fp); if (nread == -1) { mutt_error (_("error reading data object: %s\n"), gpgme_strerror (err)); unlink (tempfile); fclose (fp); return NULL; } if (ret_fp) *ret_fp = fp; return safe_strdup (tempfile);}/* Create a GpgmeRecipientSet from the keys in the string KEYLIST. The keys must be space delimited. */static gpgme_key_t *create_recipient_set (const char *keylist, gpgme_protocol_t protocol){ int err; const char *s; char buf[100]; int i; gpgme_key_t *rset = NULL; unsigned int rset_n = 0; gpgme_key_t key = NULL; gpgme_ctx_t context = NULL; err = gpgme_new (&context); if (! err) err = gpgme_set_protocol (context, protocol); if (! err) { s = keylist; do { while (*s == ' ') s++; for (i=0; *s && *s != ' ' && i < sizeof(buf)-1;) buf[i++] = *s++; buf[i] = 0; if (*buf) { if (i>1 && buf[i-1] == '!') { /* The user selected to override the valididy of that key. */ buf[i-1] = 0; err = gpgme_get_key (context, buf, &key, 0); if (! err) key->uids->validity = GPGME_VALIDITY_FULL; buf[i-1] = '!'; } else err = gpgme_get_key (context, buf, &key, 0); if (! err) { safe_realloc (&rset, sizeof (*rset) * (rset_n + 1)); rset[rset_n++] = key; } else { mutt_error (_("error adding recipient `%s': %s\n"), buf, gpgme_strerror (err)); FREE (&rset); return NULL; } } } while (*s); } /* NULL terminate. */ safe_realloc (&rset, sizeof (*rset) * (rset_n + 1)); rset[rset_n++] = NULL; if (context) gpgme_release (context); return rset;}/* Make sure that the correct signer is set. Returns 0 on success. */static int set_signer (gpgme_ctx_t ctx, int for_smime){ char *signid = for_smime ? SmimeDefaultKey: PgpSignAs; gpgme_error_t err; gpgme_ctx_t listctx; gpgme_key_t key, key2; if (!signid || !*signid) return 0; listctx = create_gpgme_context (for_smime); err = gpgme_op_keylist_start (listctx, signid, 1); if (!err) err = gpgme_op_keylist_next (listctx, &key); if (err) { gpgme_release (listctx); mutt_error (_("secret key `%s' not found: %s\n"), signid, gpgme_strerror (err)); return -1; } err = gpgme_op_keylist_next (listctx, &key2); if (!err) { gpgme_key_release (key); gpgme_key_release (key2); gpgme_release (listctx); mutt_error (_("ambiguous specification of secret key `%s'\n"), signid); return -1; } gpgme_op_keylist_end (listctx); gpgme_release (listctx); gpgme_signers_clear (ctx); err = gpgme_signers_add (ctx, key); gpgme_key_release (key); if (err) { mutt_error (_("error setting secret key `%s': %s\n"), signid, gpgme_strerror (err)); return -1; } return 0;}/* Encrypt the gpgme data object PLAINTEXT to the recipients in RSET and return an allocated filename to a temporary file containing the enciphered text. With USE_SMIME set to true, the smime backend is used. With COMBINED_SIGNED a PGP message is signed and encrypted. Returns NULL in case of error */static char *encrypt_gpgme_object (gpgme_data_t plaintext, gpgme_key_t *rset, int use_smime, int combined_signed){ int err; gpgme_ctx_t ctx; gpgme_data_t ciphertext; char *outfile; ctx = create_gpgme_context (use_smime); if (!use_smime) gpgme_set_armor (ctx, 1); ciphertext = create_gpgme_data (); if (combined_signed) { if (set_signer (ctx, use_smime)) { gpgme_data_release (ciphertext); gpgme_release (ctx); return NULL; } err = gpgme_op_encrypt_sign (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext); } else err = gpgme_op_encrypt (ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext); mutt_need_hard_redraw (); if (err) { mutt_error (_("error encrypting data: %s\n"), gpgme_strerror (err)); gpgme_data_release (ciphertext); gpgme_release (ctx); return NULL; } gpgme_release (ctx); outfile = data_object_to_tempfile (ciphertext, NULL); gpgme_data_release (ciphertext); return outfile;}/* Find the "micalg" parameter from the last Gpgme operation on context CTX. It is expected that this operation was a sign operation. Return the algorithm name as a C string in buffer BUF which must have been allocated by the caller with size BUFLEN. Returns 0 on success or -1 in case of an error. The return string is truncted to BUFLEN - 1. */static int get_micalg (gpgme_ctx_t ctx, char *buf, size_t buflen){ gpgme_sign_result_t result = NULL; const char *algorithm_name = NULL; if (!buflen) return -1; *buf = 0; result = gpgme_op_sign_result (ctx); if (result) { algorithm_name = gpgme_hash_algo_name (result->signatures->hash_algo); if (algorithm_name) { strncpy (buf, algorithm_name, buflen - 1); buf[buflen - 1] = 0; } } return *buf? 0:-1;}static void print_time(time_t t, STATE *s){ char p[STRING]; setlocale (LC_TIME, "");#ifdef HAVE_LANGINFO_D_T_FMT strftime (p, sizeof (p), nl_langinfo (D_T_FMT), localtime (&t));#else strftime (p, sizeof (p), "%c", localtime (&t));#endif setlocale (LC_TIME, "C"); state_attach_puts (p, s);}/* * Implementation of `sign_message'. *//* Sign the MESSAGE in body A either using OpenPGP or S/MIME when USE_SMIME is passed as true. Returns the new body or NULL on error. */static BODY *sign_message (BODY *a, int use_smime){ BODY *t; char *sigfile; int err = 0; char buf[100]; gpgme_ctx_t ctx; gpgme_data_t message, signature; convert_to_7bit (a); /* Signed data _must_ be in 7-bit format. */ message = body_to_data_object (a, 1); if (!message) return NULL; signature = create_gpgme_data (); ctx = create_gpgme_context (use_smime); if (!use_smime) gpgme_set_armor (ctx, 1); if (set_signer (ctx, use_smime)) { gpgme_data_release (signature); gpgme_release (ctx); return NULL; } err = gpgme_op_sign (ctx, message, signature, GPGME_SIG_MODE_DETACH ); mutt_need_hard_redraw (); gpgme_data_release (message); if (err) { gpgme_data_release (signature); gpgme_release (ctx); mutt_error (_("error signing data: %s\n"), gpgme_strerror (err)); return NULL; } sigfile = data_object_to_tempfile (signature, NULL); gpgme_data_release (signature); if (!sigfile) { gpgme_release (ctx); return NULL; } t = mutt_new_body (); t->type = TYPEMULTIPART; t->subtype = safe_strdup ("signed"); t->encoding = ENC7BIT; t->use_disp = 0; t->disposition = DISPINLINE; mutt_generate_boundary (&t->parameter); mutt_set_parameter ("protocol", use_smime? "application/pkcs7-signature" : "application/pgp-signature", &t->parameter); /* Get the micalg from gpgme. Old gpgme versions don't support this for S/MIME so we assume sha-1 in this case. */ if (!get_micalg (ctx, buf, sizeof buf)) mutt_set_parameter ("micalg", buf, &t->parameter); else if (use_smime) mutt_set_parameter ("micalg", "sha1", &t->parameter); gpgme_release (ctx); t->parts = a; a = t; t->parts->next = mutt_new_body (); t = t->parts->next; t->type = TYPEAPPLICATION; if (use_smime) { t->subtype = safe_strdup ("pkcs7-signature"); mutt_set_parameter ("name", "smime.p7s", &t->parameter); t->encoding = ENCBASE64; t->use_disp = 1; t->disposition = DISPATTACH; t->d_filename = safe_strdup ("smime.p7s"); } else { t->subtype = safe_strdup ("pgp-signature"); t->use_disp = 0; t->disposition = DISPINLINE; t->encoding = ENC7BIT; } t->filename = sigfile; t->unlink = 1; /* ok to remove this file after sending. */ return a;}BODY *pgp_gpgme_sign_message (BODY *a){ return sign_message (a, 0);}BODY *smime_gpgme_sign_message (BODY *a){ return sign_message (a, 1);}/* * Implementation of `encrypt_message'. *//* Encrypt the mail body A to all keys given as space separated keyids or fingerprints in KEYLIST and return the encrypted body. */BODY *pgp_gpgme_encrypt_message (BODY *a, char *keylist, int sign){ char *outfile = NULL; BODY *t; gpgme_key_t *rset = NULL; gpgme_data_t plaintext; rset = create_recipient_set (keylist, GPGME_PROTOCOL_OpenPGP); if (!rset) return NULL; if (sign) convert_to_7bit (a); plaintext = body_to_data_object (a, 0); if (!plaintext) { FREE (&rset); return NULL; } outfile = encrypt_gpgme_object (plaintext, rset, 0, sign); gpgme_data_release (plaintext); FREE (&rset); if (!outfile) return NULL; t = mutt_new_body (); t->type = TYPEMULTIPART; t->subtype = safe_strdup ("encrypted"); t->encoding = ENC7BIT; t->use_disp = 0; t->disposition = DISPINLINE; mutt_generate_boundary(&t->parameter); mutt_set_parameter("protocol", "application/pgp-encrypted", &t->parameter); t->parts = mutt_new_body (); t->parts->type = TYPEAPPLICATION; t->parts->subtype = safe_strdup ("pgp-encrypted"); t->parts->encoding = ENC7BIT; t->parts->next = mutt_new_body (); t->parts->next->type = TYPEAPPLICATION; t->parts->next->subtype = safe_strdup ("octet-stream"); t->parts->next->encoding = ENC7BIT; t->parts->next->filename = outfile; t->parts->next->use_disp = 1; t->parts->next->disposition = DISPINLINE; t->parts->next->unlink = 1; /* delete after sending the message */ t->parts->next->d_filename = safe_strdup ("msg.asc"); /* non pgp/mime can save */ return t;}/* * Implementation of `smime_build_smime_entity'. *//* Encrypt the mail body A to all keys given as space separated fingerprints in KEYLIST and return the S/MIME encrypted body. */BODY *smime_gpgme_build_smime_entity (BODY *a, char *keylist){ char *outfile = NULL; BODY *t; gpgme_key_t *rset = NULL; gpgme_data_t plaintext; rset = create_recipient_set (keylist, GPGME_PROTOCOL_CMS); if (!rset) return NULL; plaintext = body_to_data_object (a, 0); if (!plaintext) { FREE (&rset); return NULL; } outfile = encrypt_gpgme_object (plaintext, rset, 1, 0); gpgme_data_release (plaintext); FREE (&rset); if (!outfile) return NULL; t = mutt_new_body (); t->type = TYPEAPPLICATION; t->subtype = safe_strdup ("pkcs7-mime"); mutt_set_parameter ("name", "smime.p7m", &t->parameter); mutt_set_parameter ("smime-type", "enveloped-data", &t->parameter); t->encoding = ENCBASE64; /* The output of OpenSSL SHOULD be binary */ t->use_disp = 1; t->disposition = DISPATTACH; t->d_filename = safe_strdup ("smime.p7m"); t->filename = outfile; t->unlink = 1; /*delete after sending the message */ t->parts=0; t->next=0; return t;}/* * Implementation of `verify_one'. *//* Display the common attributes of the signature summary SUM. Return 1 if there is is a severe warning. */static int show_sig_summary (unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, STATE *s){ int severe = 0; if ((sum & GPGME_SIGSUM_KEY_REVOKED)) { state_attach_puts (_("Warning: One of the keys has been revoked\n"),s); severe = 1; } if ((sum & GPGME_SIGSUM_KEY_EXPIRED)) { time_t at = key->subkeys->expires ? key->subkeys->expires : 0; if (at) { state_attach_puts (_("Warning: The key used to create the " "signature expired at: "), s); print_time (at , s); state_attach_puts ("\n", s); } else state_attach_puts (_("Warning: At least one certification key "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -