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

📄 ssl.c

📁 文件传输协议linux 下vsftpd2.1.0.tar.gz
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Part of Very Secure FTPd * Licence: GPL v2. Note that this code interfaces with with the OpenSSL * libraries, so please read LICENSE where I give explicit permission to link * against the OpenSSL libraries. * Author: Chris Evans * ssl.c * * Routines to handle a SSL/TLS-based implementation of RFC 2228, i.e. * encryption. */#include "ssl.h"#include "session.h"#include "ftpcodes.h"#include "ftpcmdio.h"#include "defs.h"#include "str.h"#include "sysutil.h"#include "tunables.h"#include "utility.h"#include "builddefs.h"#include "logging.h"#ifdef VSF_BUILD_SSL#include <openssl/ssl.h>#include <openssl/err.h>#include <openssl/rand.h>#include <openssl/bio.h>#include <errno.h>static char* get_ssl_error();static SSL* get_ssl(struct vsf_session* p_sess, int fd);static int ssl_session_init(struct vsf_session* p_sess);static void setup_bio_callbacks();static long bio_callback(  BIO* p_bio, int oper, const char* p_arg, int argi, long argl, long retval);static int ssl_verify_callback(int verify_ok, X509_STORE_CTX* p_ctx);static int ssl_cert_digest(  SSL* p_ssl, struct vsf_session* p_sess, struct mystr* p_str);static void maybe_log_shutdown_state(struct vsf_session* p_sess);static void maybe_log_ssl_error_state(struct vsf_session* p_sess, int ret);static int ssl_read_common(struct vsf_session* p_sess,                           SSL* p_ssl,                           char* p_buf,                           unsigned int len,                           int (*p_ssl_func)(SSL*, void*, int));static int ssl_inited;static struct mystr debug_str;voidssl_init(struct vsf_session* p_sess){  if (!ssl_inited)  {    SSL_CTX* p_ctx;    long options;    int verify_option = 0;    SSL_library_init();    p_ctx = SSL_CTX_new(SSLv23_server_method());    if (p_ctx == NULL)    {      die("SSL: could not allocate SSL context");    }    options = SSL_OP_ALL;    if (!tunable_sslv2)    {      options |= SSL_OP_NO_SSLv2;    }    if (!tunable_sslv3)    {      options |= SSL_OP_NO_SSLv3;    }    if (!tunable_tlsv1)    {      options |= SSL_OP_NO_TLSv1;    }    SSL_CTX_set_options(p_ctx, options);    if (tunable_rsa_cert_file)    {      const char* p_key = tunable_rsa_private_key_file;      if (!p_key)      {        p_key = tunable_rsa_cert_file;      }      if (SSL_CTX_use_certificate_chain_file(p_ctx, tunable_rsa_cert_file) != 1)      {        die("SSL: cannot load RSA certificate");      }      if (SSL_CTX_use_PrivateKey_file(p_ctx, p_key, X509_FILETYPE_PEM) != 1)      {        die("SSL: cannot load RSA private key");      }    }    if (tunable_dsa_cert_file)    {      const char* p_key = tunable_dsa_private_key_file;      if (!p_key)      {        p_key = tunable_dsa_cert_file;      }      if (SSL_CTX_use_certificate_chain_file(p_ctx, tunable_dsa_cert_file) != 1)      {        die("SSL: cannot load DSA certificate");      }      if (SSL_CTX_use_PrivateKey_file(p_ctx, p_key, X509_FILETYPE_PEM) != 1)      {        die("SSL: cannot load DSA private key");      }    }    if (tunable_ssl_ciphers &&        SSL_CTX_set_cipher_list(p_ctx, tunable_ssl_ciphers) != 1)    {      die("SSL: could not set cipher list");    }    if (RAND_status() != 1)    {      die("SSL: RNG is not seeded");    }    if (tunable_ssl_request_cert)    {      verify_option |= SSL_VERIFY_PEER;    }    if (tunable_require_cert)    {      verify_option |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;    }    if (verify_option)    {      SSL_CTX_set_verify(p_ctx, verify_option, ssl_verify_callback);      if (tunable_ca_certs_file)      {        if (!SSL_CTX_load_verify_locations(p_ctx, tunable_ca_certs_file, NULL))        {          die("SSL: could not load verify file");        }      }    }    {      char* p_ctx_id = "vsftpd";      SSL_CTX_set_session_id_context(p_ctx, (void*) p_ctx_id,                                     vsf_sysutil_strlen(p_ctx_id));    }    p_sess->p_ssl_ctx = p_ctx;    ssl_inited = 1;  }}voidssl_control_handshake(struct vsf_session* p_sess){  if (!ssl_session_init(p_sess))  {    struct mystr err_str = INIT_MYSTR;    str_alloc_text(&err_str, "Negotiation failed: ");    /* Technically, we shouldn't leak such detailed error messages. */    str_append_text(&err_str, get_ssl_error());    vsf_cmdio_write_str(p_sess, FTP_TLS_FAIL, &err_str);    vsf_sysutil_exit(0);  }  p_sess->control_use_ssl = 1;}voidhandle_auth(struct vsf_session* p_sess){  str_upper(&p_sess->ftp_arg_str);  if (str_equal_text(&p_sess->ftp_arg_str, "TLS") ||      str_equal_text(&p_sess->ftp_arg_str, "TLS-C") ||      str_equal_text(&p_sess->ftp_arg_str, "SSL") ||      str_equal_text(&p_sess->ftp_arg_str, "TLS-P"))  {    vsf_cmdio_write(p_sess, FTP_AUTHOK, "Proceed with negotiation.");    ssl_control_handshake(p_sess);    if (str_equal_text(&p_sess->ftp_arg_str, "SSL") ||        str_equal_text(&p_sess->ftp_arg_str, "TLS-P"))    {      p_sess->data_use_ssl = 1;    }  }  else  {    vsf_cmdio_write(p_sess, FTP_BADAUTH, "Unknown AUTH type.");  }}voidhandle_pbsz(struct vsf_session* p_sess){  if (!p_sess->control_use_ssl)  {    vsf_cmdio_write(p_sess, FTP_BADPBSZ, "PBSZ needs a secure connection.");  }  else  {    vsf_cmdio_write(p_sess, FTP_PBSZOK, "PBSZ set to 0.");  }}voidhandle_prot(struct vsf_session* p_sess){  str_upper(&p_sess->ftp_arg_str);  if (!p_sess->control_use_ssl)  {    vsf_cmdio_write(p_sess, FTP_BADPROT, "PROT needs a secure connection.");  }  else if (str_equal_text(&p_sess->ftp_arg_str, "C"))  {    p_sess->data_use_ssl = 0;    vsf_cmdio_write(p_sess, FTP_PROTOK, "PROT now Clear.");  }  else if (str_equal_text(&p_sess->ftp_arg_str, "P"))  {    p_sess->data_use_ssl = 1;    vsf_cmdio_write(p_sess, FTP_PROTOK, "PROT now Private.");  }  else if (str_equal_text(&p_sess->ftp_arg_str, "S") ||           str_equal_text(&p_sess->ftp_arg_str, "E"))  {    vsf_cmdio_write(p_sess, FTP_NOHANDLEPROT, "PROT not supported.");  }  else  {    vsf_cmdio_write(p_sess, FTP_NOSUCHPROT, "PROT not recognized.");  }}intssl_read(struct vsf_session* p_sess, void* p_ssl, char* p_buf, unsigned int len){  return ssl_read_common(p_sess, (SSL*) p_ssl, p_buf, len, SSL_read);}intssl_peek(struct vsf_session* p_sess, void* p_ssl, char* p_buf, unsigned int len){  return ssl_read_common(p_sess, (SSL*) p_ssl, p_buf, len, SSL_peek);}static intssl_read_common(struct vsf_session* p_sess,                SSL* p_void_ssl,                char* p_buf,                unsigned int len,                int (*p_ssl_func)(SSL*, void*, int)){  int retval;  int err;  SSL* p_ssl = (SSL*) p_void_ssl;  do  {    retval = (*p_ssl_func)(p_ssl, p_buf, len);    err = SSL_get_error(p_ssl, retval);  }  while (retval < 0 && (err == SSL_ERROR_WANT_READ ||                        err == SSL_ERROR_WANT_WRITE));  // If we hit an EOF, make sure it was from the peer, not injected by the  // attacker.  if (retval == 0 && SSL_get_shutdown(p_ssl) != SSL_RECEIVED_SHUTDOWN)  {    str_alloc_text(&debug_str, "Connection terminated without SSL shutdown "                               "- buggy client?");    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);    if (tunable_strict_ssl_read_eof)    {      return -1;    }  }  return retval;}intssl_write(void* p_ssl, const char* p_buf, unsigned int len){  int retval;  int err;  do  {    retval = SSL_write((SSL*) p_ssl, p_buf, len);    err = SSL_get_error((SSL*) p_ssl, retval);  }  while (retval < 0 && (err == SSL_ERROR_WANT_READ ||                        err == SSL_ERROR_WANT_WRITE));  return retval;}intssl_write_str(void* p_ssl, const struct mystr* p_str){  unsigned int len = str_getlen(p_str);  int ret = SSL_write((SSL*) p_ssl, str_getbuf(p_str), len);  if ((unsigned int) ret != len)  {    return -1;  }  return 0;}intssl_read_into_str(struct vsf_session* p_sess, void* p_ssl, struct mystr* p_str){  unsigned int len = str_getlen(p_str);  int ret = ssl_read(p_sess, p_ssl, (char*) str_getbuf(p_str), len);  if (ret >= 0)  {    str_trunc(p_str, (unsigned int) ret);  }  else  {    str_empty(p_str);  }  return ret;}static voidmaybe_log_shutdown_state(struct vsf_session* p_sess){  if (tunable_debug_ssl)  {    int ret = SSL_get_shutdown(p_sess->p_data_ssl);    str_alloc_text(&debug_str, "SSL shutdown state is: ");    if (ret == 0)    {      str_append_text(&debug_str, "NONE");    }    else if (ret == SSL_SENT_SHUTDOWN)    {      str_append_text(&debug_str, "SSL_SENT_SHUTDOWN");    }    else if (ret == SSL_RECEIVED_SHUTDOWN)    {      str_append_text(&debug_str, "SSL_RECEIVED_SHUTDOWN");    }    else    {      str_append_ulong(&debug_str, ret);    }    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);  }}static voidmaybe_log_ssl_error_state(struct vsf_session* p_sess, int ret){  if (tunable_debug_ssl)  {    str_alloc_text(&debug_str, "SSL ret: ");    str_append_ulong(&debug_str, ret);    str_append_text(&debug_str, ", SSL error: ");    str_append_text(&debug_str, get_ssl_error());    str_append_text(&debug_str, ", errno: ");    str_append_ulong(&debug_str, errno);    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);  }}intssl_data_close(struct vsf_session* p_sess){  int success = 1;  SSL* p_ssl = p_sess->p_data_ssl;  if (p_ssl)  {    int ret;    maybe_log_shutdown_state(p_sess);    // This is a mess. Ideally, when we're the sender, we'd like to get to the    // SSL_RECEIVED_SHUTDOWN state to get a cryptographic guarantee that the    // peer received all the data and shut the connection down cleanly. It    // doesn't matter hugely apart from logging, but it's a nagging detail.    // Unfortunately, no FTP client I found was able to get sends into that    // state, so the best we can do is issue SSL_shutdown but not check the    // errors / returns. At least this enables the receiver to be sure of the    // integrity of the send in terms of unwanted truncation.    ret = SSL_shutdown(p_ssl);    maybe_log_shutdown_state(p_sess);    if (ret == 0)    {      ret = SSL_shutdown(p_ssl);      maybe_log_shutdown_state(p_sess);      if (ret != 1)      {        if (tunable_strict_ssl_write_shutdown)        {          success = 0;        }        maybe_log_shutdown_state(p_sess);        maybe_log_ssl_error_state(p_sess, ret);      }    }    else if (ret < 0)    {      if (tunable_strict_ssl_write_shutdown)      {        success = 0;      }      maybe_log_ssl_error_state(p_sess, ret);    }

⌨️ 快捷键说明

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