⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mutt_ssl.c

📁 mutt-1.5.12 源代码。linux 下邮件接受的工具。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 1999-2001 Tommi Komulainen <Tommi.Komulainen@iki.fi> *  *     This program is free software; you can redistribute it and/or modify *     it under the terms of the GNU General Public License as published by *     the Free Software Foundation; either version 2 of the License, or *     (at your option) any later version. *  *     This program is distributed in the hope that it will be useful, *     but WITHOUT ANY WARRANTY; without even the implied warranty of *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *     GNU General Public License for more details. *  *     You should have received a copy of the GNU General Public License *     along with this program; if not, write to the Free Software *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. */#if HAVE_CONFIG_H# include "config.h"#endif#include <openssl/ssl.h>#include <openssl/x509.h>#include <openssl/err.h>#include <openssl/rand.h>#undef _#include <string.h>#include "mutt.h"#include "mutt_socket.h"#include "mutt_menu.h"#include "mutt_curses.h"#include "mutt_ssl.h"#if OPENSSL_VERSION_NUMBER >= 0x00904000L#define READ_X509_KEY(fp, key)	PEM_read_X509(fp, key, NULL, NULL)#else#define READ_X509_KEY(fp, key)	PEM_read_X509(fp, key, NULL)#endif/* Just in case OpenSSL doesn't define DEVRANDOM */#ifndef DEVRANDOM#define DEVRANDOM "/dev/urandom"#endif/* This is ugly, but as RAND_status came in on OpenSSL version 0.9.5 * and the code has to support older versions too, this is seemed to * be cleaner way compared to having even uglier #ifdefs all around. */#ifdef HAVE_RAND_STATUS#define HAVE_ENTROPY()	(RAND_status() == 1)#elsestatic int entropy_byte_count = 0;/* OpenSSL fills the entropy pool from /dev/urandom if it exists */#define HAVE_ENTROPY()	(!access(DEVRANDOM, R_OK) || entropy_byte_count >= 16)#endiftypedef struct _sslsockdata{  SSL_CTX *ctx;  SSL *ssl;  X509 *cert;}sslsockdata;/* local prototypes */int ssl_init (void);static int add_entropy (const char *file);static int ssl_socket_read (CONNECTION* conn, char* buf, size_t len);static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);static int ssl_socket_open (CONNECTION * conn);static int ssl_socket_close (CONNECTION * conn);static int tls_close (CONNECTION* conn);static int ssl_check_certificate (sslsockdata * data);static void ssl_get_client_cert(sslsockdata *ssldata, CONNECTION *conn);static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata);static int ssl_negotiate (sslsockdata*);/* mutt_ssl_starttls: Negotiate TLS over an already opened connection. *   TODO: Merge this code better with ssl_socket_open. */int mutt_ssl_starttls (CONNECTION* conn){  sslsockdata* ssldata;  int maxbits;  if (ssl_init())    goto bail;  ssldata = (sslsockdata*) safe_calloc (1, sizeof (sslsockdata));  /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. */  if (! (ssldata->ctx = SSL_CTX_new (TLSv1_client_method ())))  {    dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL_CTX\n"));    goto bail_ssldata;  }  ssl_get_client_cert(ssldata, conn);  if (! (ssldata->ssl = SSL_new (ssldata->ctx)))  {    dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL\n"));    goto bail_ctx;  }  if (SSL_set_fd (ssldata->ssl, conn->fd) != 1)  {    dprint (1, (debugfile, "mutt_ssl_starttls: Error setting fd\n"));    goto bail_ssl;  }  if (ssl_negotiate (ssldata))    goto bail_ssl;  /* hmm. watch out if we're starting TLS over any method other than raw. */  conn->sockdata = ssldata;  conn->conn_read = ssl_socket_read;  conn->conn_write = ssl_socket_write;  conn->conn_close = tls_close;  conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (ssldata->ssl),    &maxbits);  return 0; bail_ssl:  FREE (&ssldata->ssl); bail_ctx:  FREE (&ssldata->ctx); bail_ssldata:  FREE (&ssldata); bail:  return -1;}/*  * OpenSSL library needs to be fed with sufficient entropy. On systems * with /dev/urandom, this is done transparently by the library itself, * on other systems we need to fill the entropy pool ourselves. * * Even though only OpenSSL 0.9.5 and later will complain about the * lack of entropy, we try to our best and fill the pool with older * versions also. (That's the reason for the ugly #ifdefs and macros, * otherwise I could have simply #ifdef'd the whole ssl_init funcion) */int ssl_init (void){  char path[_POSIX_PATH_MAX];  static unsigned char init_complete = 0;  if (init_complete)    return 0;  if (! HAVE_ENTROPY())  {    /* load entropy from files */    add_entropy (SslEntropyFile);    add_entropy (RAND_file_name (path, sizeof (path)));      /* load entropy from egd sockets */#ifdef HAVE_RAND_EGD    add_entropy (getenv ("EGDSOCKET"));    snprintf (path, sizeof(path), "%s/.entropy", NONULL(Homedir));    add_entropy (path);    add_entropy ("/tmp/entropy");#endif    /* shuffle $RANDFILE (or ~/.rnd if unset) */    RAND_write_file (RAND_file_name (path, sizeof (path)));    mutt_clear_error ();    if (! HAVE_ENTROPY())    {      mutt_error (_("Failed to find enough entropy on your system"));      mutt_sleep (2);      return -1;    }  }  /* I don't think you can do this just before reading the error. The call   * itself might clobber the last SSL error. */  SSL_load_error_strings();  SSL_library_init();  init_complete = 1;  return 0;}static int add_entropy (const char *file){  struct stat st;  int n = -1;  if (!file) return 0;  if (stat (file, &st) == -1)    return errno == ENOENT ? 0 : -1;  mutt_message (_("Filling entropy pool: %s...\n"),		file);    /* check that the file permissions are secure */  if (st.st_uid != getuid () ||       ((st.st_mode & (S_IWGRP | S_IRGRP)) != 0) ||      ((st.st_mode & (S_IWOTH | S_IROTH)) != 0))  {    mutt_error (_("%s has insecure permissions!"), file);    mutt_sleep (2);    return -1;  }#ifdef HAVE_RAND_EGD  n = RAND_egd (file);#endif  if (n <= 0)    n = RAND_load_file (file, -1);#ifndef HAVE_RAND_STATUS  if (n > 0) entropy_byte_count += n;#endif  return n;}static int ssl_socket_open_err (CONNECTION *conn){  mutt_error (_("SSL disabled due the lack of entropy"));  mutt_sleep (2);  return -1;}int mutt_ssl_socket_setup (CONNECTION * conn){  if (ssl_init() < 0)  {    conn->conn_open = ssl_socket_open_err;    return -1;  }  conn->conn_open	= ssl_socket_open;  conn->conn_read	= ssl_socket_read;  conn->conn_write	= ssl_socket_write;  conn->conn_close	= ssl_socket_close;  conn->conn_poll       = raw_socket_poll;  return 0;}static int ssl_socket_read (CONNECTION* conn, char* buf, size_t len){  sslsockdata *data = conn->sockdata;  return SSL_read (data->ssl, buf, len);}static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len){  sslsockdata *data = conn->sockdata;  return SSL_write (data->ssl, buf, len);}static int ssl_socket_open (CONNECTION * conn){  sslsockdata *data;  int maxbits;  if (raw_socket_open (conn) < 0)    return -1;  data = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata));  conn->sockdata = data;  data->ctx = SSL_CTX_new (SSLv23_client_method ());  /* disable SSL protocols as needed */  if (!option(OPTTLSV1))   {    SSL_CTX_set_options(data->ctx, SSL_OP_NO_TLSv1);  }  if (!option(OPTSSLV2))   {    SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv2);  }  if (!option(OPTSSLV3))   {    SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv3);  }  ssl_get_client_cert(data, conn);  data->ssl = SSL_new (data->ctx);  SSL_set_fd (data->ssl, conn->fd);  if (ssl_negotiate(data))  {    mutt_socket_close (conn);    return -1;  }    conn->ssf = SSL_CIPHER_get_bits (SSL_get_current_cipher (data->ssl),    &maxbits);  return 0;}/* ssl_negotiate: After SSL state has been initialised, attempt to negotiate *   SSL over the wire, including certificate checks. */static int ssl_negotiate (sslsockdata* ssldata){  int err;  const char* errmsg;#if OPENSSL_VERSION_NUMBER >= 0x00906000L  /* This only exists in 0.9.6 and above. Without it we may get interrupted   *   reads or writes. Bummer. */  SSL_set_mode (ssldata->ssl, SSL_MODE_AUTO_RETRY);#endif  if ((err = SSL_connect (ssldata->ssl)) != 1)  {    switch (SSL_get_error (ssldata->ssl, err))    {    case SSL_ERROR_SYSCALL:      errmsg = _("I/O error");      break;    case SSL_ERROR_SSL:      errmsg = ERR_error_string (ERR_get_error (), NULL);      break;    default:      errmsg = _("unknown error");    }        mutt_error (_("SSL failed: %s"), errmsg);    mutt_sleep (1);    return -1;  }  ssldata->cert = SSL_get_peer_certificate (ssldata->ssl);  if (!ssldata->cert)  {    mutt_error (_("Unable to get certificate from peer"));    mutt_sleep (1);    return -1;  }  if (!ssl_check_certificate (ssldata))    return -1;  mutt_message (_("SSL connection using %s (%s)"),     SSL_get_cipher_version (ssldata->ssl), SSL_get_cipher_name (ssldata->ssl));  mutt_sleep (0);  return 0;}static int ssl_socket_close (CONNECTION * conn){  sslsockdata *data = conn->sockdata;  if (data)  {    SSL_shutdown (data->ssl);    /* hold onto this for the life of mutt, in case we want to reconnect.     * The purist in me wants a mutt_exit hook. */#if 0    X509_free (data->cert);#endif    SSL_free (data->ssl);    SSL_CTX_free (data->ctx);    FREE (&conn->sockdata);  }  return raw_socket_close (conn);}static int tls_close (CONNECTION* conn){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -