📄 mutt_ssl.c
字号:
int rc; rc = ssl_socket_close (conn); conn->conn_read = raw_socket_read; conn->conn_write = raw_socket_write; conn->conn_close = raw_socket_close; return rc;}static char *x509_get_part (char *line, const char *ndx){ static char ret[SHORT_STRING]; char *c, *c2; strfcpy (ret, _("Unknown"), sizeof (ret)); c = strstr (line, ndx); if (c) { c += strlen (ndx); c2 = strchr (c, '/'); if (c2) *c2 = '\0'; strfcpy (ret, c, sizeof (ret)); if (c2) *c2 = '/'; } return ret;}static void x509_fingerprint (char *s, int l, X509 * cert){ unsigned char md[EVP_MAX_MD_SIZE]; unsigned int n; int j; if (!X509_digest (cert, EVP_md5 (), md, &n)) { snprintf (s, l, _("[unable to calculate]")); } else { for (j = 0; j < (int) n; j++) { char ch[8]; snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : "")); safe_strcat (s, l, ch); } }}static char *asn1time_to_string (ASN1_UTCTIME *tm){ static char buf[64]; BIO *bio; strfcpy (buf, _("[invalid date]"), sizeof (buf)); bio = BIO_new (BIO_s_mem()); if (bio) { if (ASN1_TIME_print (bio, tm)) (void) BIO_read (bio, buf, sizeof (buf)); BIO_free (bio); } return buf;}static int check_certificate_by_signer (X509 *peercert){ X509_STORE_CTX xsc; X509_STORE *ctx; int pass = 0; ctx = X509_STORE_new (); if (ctx == NULL) return 0; if (option (OPTSSLSYSTEMCERTS)) { if (X509_STORE_set_default_paths (ctx)) pass++; else dprint (2, (debugfile, "X509_STORE_set_default_paths failed\n")); } if (X509_STORE_load_locations (ctx, SslCertFile, NULL)) pass++; else dprint (2, (debugfile, "X509_STORE_load_locations_failed\n")); if (pass == 0) { /* nothing to do */ X509_STORE_free (ctx); return 0; } X509_STORE_CTX_init (&xsc, ctx, peercert, NULL); pass = (X509_verify_cert (&xsc) > 0);#ifdef DEBUG if (! pass) { char buf[SHORT_STRING]; int err; err = X509_STORE_CTX_get_error (&xsc); snprintf (buf, sizeof (buf), "%s (%d)", X509_verify_cert_error_string(err), err); dprint (2, (debugfile, "X509_verify_cert: %s\n", buf)); }#endif X509_STORE_CTX_cleanup (&xsc); X509_STORE_free (ctx); return pass;}static int compare_certificates (X509 *cert, X509 *peercert, unsigned char *peermd, unsigned int peermdlen){ unsigned char md[EVP_MAX_MD_SIZE]; unsigned int mdlen; /* Avoid CPU-intensive digest calculation if the certificates are * not even remotely equal. */ if (X509_subject_name_cmp (cert, peercert) != 0 || X509_issuer_name_cmp (cert, peercert) != 0) return -1; if (!X509_digest (cert, EVP_sha1(), md, &mdlen) || peermdlen != mdlen) return -1; if (memcmp(peermd, md, mdlen) != 0) return -1; return 0;}static int check_certificate_cache (X509 *peercert){ unsigned char peermd[EVP_MAX_MD_SIZE]; unsigned int peermdlen; X509 *cert; LIST *scert; if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen)) { return 0; } for (scert = SslSessionCerts; scert; scert = scert->next) { cert = *(X509**)scert->data; if (!compare_certificates (cert, peercert, peermd, peermdlen)) { return 1; } } return 0;}static int check_certificate_by_digest (X509 *peercert){ unsigned char peermd[EVP_MAX_MD_SIZE]; unsigned int peermdlen; X509 *cert = NULL; int pass = 0; FILE *fp; /* expiration check */ if (X509_cmp_current_time (X509_get_notBefore (peercert)) >= 0) { dprint (2, (debugfile, "Server certificate is not yet valid\n")); mutt_error (_("Server certificate is not yet valid")); mutt_sleep (2); return 0; } if (X509_cmp_current_time (X509_get_notAfter (peercert)) <= 0) { dprint (2, (debugfile, "Server certificate has expired")); mutt_error (_("Server certificate has expired")); mutt_sleep (2); return 0; } if ((fp = fopen (SslCertFile, "rt")) == NULL) return 0; if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen)) { fclose (fp); return 0; } while ((cert = READ_X509_KEY (fp, &cert)) != NULL) { pass = compare_certificates (cert, peercert, peermd, peermdlen) ? 0 : 1; if (pass) break; } X509_free (cert); fclose (fp); return pass;}static int ssl_check_certificate (sslsockdata * data){ char *part[] = {"/CN=", "/Email=", "/O=", "/OU=", "/L=", "/ST=", "/C="}; char helpstr[SHORT_STRING]; char buf[SHORT_STRING]; MUTTMENU *menu; int done, row, i; FILE *fp; char *name = NULL, *c; /* check session cache first */ if (check_certificate_cache (data->cert)) { dprint (1, (debugfile, "ssl_check_certificate: using cached certificate\n")); return 1; } if (check_certificate_by_signer (data->cert)) { dprint (1, (debugfile, "ssl_check_certificate: signer check passed\n")); return 1; } /* automatic check from user's database */ if (SslCertFile && check_certificate_by_digest (data->cert)) { dprint (1, (debugfile, "ssl_check_certificate: digest check passed\n")); return 1; } /* interactive check from user */ menu = mutt_new_menu (); menu->max = 19; menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *)); for (i = 0; i < menu->max; i++) menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char)); row = 0; strfcpy (menu->dialog[row], _("This certificate belongs to:"), SHORT_STRING); row++; name = X509_NAME_oneline (X509_get_subject_name (data->cert), buf, sizeof (buf)); for (i = 0; i < 5; i++) { c = x509_get_part (name, part[i]); snprintf (menu->dialog[row++], SHORT_STRING, " %s", c); } row++; strfcpy (menu->dialog[row], _("This certificate was issued by:"), SHORT_STRING); row++; name = X509_NAME_oneline (X509_get_issuer_name (data->cert), buf, sizeof (buf)); for (i = 0; i < 5; i++) { c = x509_get_part (name, part[i]); snprintf (menu->dialog[row++], SHORT_STRING, " %s", c); } row++; snprintf (menu->dialog[row++], SHORT_STRING, _("This certificate is valid")); snprintf (menu->dialog[row++], SHORT_STRING, _(" from %s"), asn1time_to_string (X509_get_notBefore (data->cert))); snprintf (menu->dialog[row++], SHORT_STRING, _(" to %s"), asn1time_to_string (X509_get_notAfter (data->cert))); row++; buf[0] = '\0'; x509_fingerprint (buf, sizeof (buf), data->cert); snprintf (menu->dialog[row++], SHORT_STRING, _("Fingerprint: %s"), buf); menu->title = _("SSL Certificate check"); if (SslCertFile && X509_cmp_current_time (X509_get_notAfter (data->cert)) >= 0 && X509_cmp_current_time (X509_get_notBefore (data->cert)) < 0) { menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); menu->keys = _("roa"); } else { menu->prompt = _("(r)eject, accept (o)nce"); menu->keys = _("ro"); } helpstr[0] = '\0'; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT); safe_strcat (helpstr, sizeof (helpstr), buf); mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP); safe_strcat (helpstr, sizeof (helpstr), buf); menu->help = helpstr; done = 0; set_option(OPTUNBUFFEREDINPUT); while (!done) { switch (mutt_menuLoop (menu)) { case -1: /* abort */ case OP_MAX + 1: /* reject */ case OP_EXIT: done = 1; break; case OP_MAX + 3: /* accept always */ done = 0; if ((fp = fopen (SslCertFile, "a"))) { if (PEM_write_X509 (fp, data->cert)) done = 1; fclose (fp); } if (!done) { mutt_error (_("Warning: Couldn't save certificate")); mutt_sleep (2); } else { mutt_message (_("Certificate saved")); mutt_sleep (0); } /* fall through */ case OP_MAX + 2: /* accept once */ done = 2; /* keep a handle on accepted certificates in case we want to * open up another connection to the same server in this session */ SslSessionCerts = mutt_add_list_n (SslSessionCerts, &data->cert, sizeof (X509 **)); break; } } unset_option(OPTUNBUFFEREDINPUT); mutt_menuDestroy (&menu); return (done == 2);}static void ssl_get_client_cert(sslsockdata *ssldata, CONNECTION *conn){ if (SslClientCert) { dprint (2, (debugfile, "Using client certificate %s\n", SslClientCert)); SSL_CTX_set_default_passwd_cb_userdata(ssldata->ctx, &conn->account); SSL_CTX_set_default_passwd_cb(ssldata->ctx, ssl_passwd_cb); SSL_CTX_use_certificate_file(ssldata->ctx, SslClientCert, SSL_FILETYPE_PEM); SSL_CTX_use_PrivateKey_file(ssldata->ctx, SslClientCert, SSL_FILETYPE_PEM); }}static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata){ ACCOUNT *account = (ACCOUNT*)userdata; if (mutt_account_getuser (account)) return 0; dprint (2, (debugfile, "ssl_passwd_cb: getting password for %s@%s:%u\n", account->user, account->host, account->port)); if (mutt_account_getpass (account)) return 0; return snprintf(buf, size, "%s", account->pass);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -