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

📄 ssl.c

📁 resinweb服务器源文件
💻 C
字号:
/* * Copyright (c) 1998-2002 Caucho Technology -- all rights reserved * * Caucho Technology permits modification and use of this file in * source and binary form ("the Software") subject to the Caucho * Developer Source License 1.1 ("the License") which accompanies * this file.  The License is also available at *   http://www.caucho.com/download/cdsl1-1.xtp * * In addition to the terms of the License, the following conditions * must be met: * * 1. Each copy or derived work of the Software must preserve the copyright *    notice and this notice unmodified. * * 2. Each copy of the Software in source or binary form must include  *    an unmodified copy of the License in a plain ASCII text file named *    LICENSE. * * 3. Caucho reserves all rights to its names, trademarks and logos. *    In particular, the names "Resin" and "Caucho" are trademarks of *    Caucho and may not be used to endorse products derived from *    this software.  "Resin" and "Caucho" may not appear in the names *    of products derived from this software. * * This Software is provided "AS IS," without a warranty of any kind.  * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. * * CAUCHO TECHNOLOGY AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR * DISTRIBUTING SOFTWARE. IN NO EVENT WILL CAUCHO OR ITS LICENSORS BE LIABLE * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGES.       * * @author Scott Ferguson */#include <stdio.h>#ifdef WIN32#include <windows.h>#else#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <sys/time.h>#endif#include <stdlib.h>#include <memory.h>#include <errno.h>#include <sys/types.h>#include <fcntl.h>/* SSLeay stuff */#include <openssl/ssl.h>#include <openssl/rsa.h>       #include <openssl/err.h>#ifdef SSL_ENGINE#include <openssl/engine.h>#endif#include <jni.h>#include "../common/cse.h"#include "resin.h"#include "resin_jni.h"static int ssl_open(connection_t *conn, int fd);static int ssl_read(connection_t *conn, char *buf, int len);static int ssl_write(connection_t *conn, char *buf, int len);static int ssl_close(connection_t *conn);static void ssl_free(connection_t *conn);static int ssl_read_client_certificate(connection_t *conn, char *buf, int len);static connection_t *ssl_accept(server_socket_t *ss);struct connection_ops_t ssl_ops = {  ssl_open,  ssl_read,  ssl_write,  ssl_close,  ssl_free,  ssl_read_client_certificate,};static RSA *g_rsa_512 = 0;static RSA *g_rsa_1024 = 0;static intexception_status(connection_t *conn, int error){  if (error == EINTR || error == EAGAIN)    return INTERRUPT_EXN;  else if (error == EPIPE || errno == ECONNRESET) {    conn->ops->close(conn);    return DISCONNECT_EXN;  }  else {    conn->ops->close(conn);    return -1;  }}static intpassword_callback(char *buf, int size, int rwflag, void *userdata){  strcpy(buf, userdata);  return strlen(buf);}/* * This OpenSSL callback function is called when OpenSSL * does client authentication and verifies the certificate chain. */static intssl_verify_callback(int ok, X509_STORE_CTX *ctx){  SSL *ssl;  connection_t *conn;  int error_code;  /* If openssl's check was okay, then the verify is okay. */  if (ok)    return 1;  ssl = (SSL *) X509_STORE_CTX_get_app_data(ctx);  /* If the user data is missing, then it's a failure. */  if (! ssl)    return 0;    conn = (connection_t *) SSL_get_app_data(ssl);  /* If the user data is missing, then it's a failure. */  if (! conn || ! conn->ss)    return 0;    error_code = X509_STORE_CTX_get_error(ctx);  /* optional and required do require valid certificates */  if (conn->ss->verify_client != Q_VERIFY_OPTIONAL_NO_CA)    return 0;  if (error_code == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||      error_code == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||      error_code == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||      error_code == X509_V_ERR_CERT_UNTRUSTED ||      error_code == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)    return 1;  return 0;}static SSL_CTX *ssl_create_context(ssl_config_t *config){  SSL_CTX *ctx;  SSL_METHOD *meth;  int skip_first;  SSL_load_error_strings();  SSL_library_init();  SSLeay_add_ssl_algorithms();  meth = SSLv23_server_method();#ifdef SSL_ENGINE  if (config->crypto_device && ! strcmp(config->crypto_device, "builtin")) {    ENGINE *e = ENGINE_by_id(config->crypto_device);    if (! e) {      printf("unknown crypto device `%s'\n", config->crypto_device);      return 0;    }        if (! ENGINE_set_default(e, ENGINE_METHOD_ALL)) {      printf("Can't initialize crypto device `%s'\n", config->crypto_device);      return 0;    }    printf("using crypto-device `%s'\n", config->crypto_device);    ENGINE_free(e);  }#endif    ctx = SSL_CTX_new(meth);    if (! ctx) {    /* ERR_print_errors_fp(stderr); */    printf("can't allocate context\n");    return 0;  }  SSL_CTX_set_options(ctx, SSL_OP_ALL);  if (! (config->alg_flags & ALG_SSL2))    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);  if (! (config->alg_flags & ALG_SSL3))    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);  if (! (config->alg_flags & ALG_TLS1))    SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);  if (! config->key_file) {    fprintf(stderr, "Can't find certificate-key-file in SSL configuration\n");    return 0;  }    if (! config->password) {    fprintf(stderr, "Can't find key-store-password in SSL configuration\n");    return 0;  }  SSL_CTX_set_default_passwd_cb(ctx, password_callback);  SSL_CTX_set_default_passwd_cb_userdata(ctx, config->password);  if (SSL_CTX_use_certificate_file(ctx, config->certificate_file,                                   SSL_FILETYPE_PEM) <= 0) {    fprintf(stderr, "Can't open certificate file %s\n",            config->certificate_file);    ERR_print_errors_fp(stderr);    return 0;  }    if (SSL_CTX_use_PrivateKey_file(ctx,                                  config->key_file,                                  SSL_FILETYPE_PEM) <= 0) {    ERR_print_errors_fp(stderr);    return 0;  }  if (! SSL_CTX_check_private_key(ctx)) {    fprintf(stderr, "Private key does not match the certificate public key\n");    return 0;  }  if (config->certificate_chain_file &&      SSL_CTX_use_certificate_chain_file(ctx, config->certificate_chain_file)) {    ERR_print_errors_fp(stderr);    fprintf(stderr, "Can't open certificate chain file %s\n",            config->certificate_chain_file);    return 0;  }  if (config->verify_client != Q_VERIFY_NONE) {    int nVerify = SSL_VERIFY_NONE|SSL_VERIFY_PEER;    if (config->verify_client == Q_VERIFY_REQUIRE)      nVerify |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;    SSL_CTX_set_verify(ctx, nVerify, ssl_verify_callback);  }  if (! g_rsa_512) {    g_rsa_512 = RSA_generate_key(512, RSA_F4, NULL, NULL);        if (! g_rsa_512) {      fprintf(stderr, "Can't generate 512 bit key.\n");      return 0;    }  }  if (! g_rsa_1024) {    g_rsa_1024 = RSA_generate_key(1024, RSA_F4, NULL, NULL);        if (! g_rsa_1024) {      fprintf(stderr, "Can't generate 1024 bit key.\n");      return 0;    }  }  return ctx;}static connection_t *ssl_accept(server_socket_t *ss){  connection_t *conn;  conn = std_accept(ss);  if (! conn)    return 0;  if (! conn->context) {    conn->context = ssl_create_context(ss->ssl_config);  }  conn->ops = &ssl_ops;  conn->ssl_lock = &ss->ssl_lock;    return conn;}static voidssl_safe_free(int fd, SSL *ssl){  if (ssl) {    int count;    /* clear non-blocking i/o */#ifndef WIN32    {      int flags;      flags = fcntl(fd, F_GETFL);      fcntl(fd, F_SETFL, ~O_NONBLOCK&flags);    }#endif      /* SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); */    SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);    for (count = 4; count > 0; count--) {      int result = SSL_shutdown(ssl);    }        SSL_free(ssl);  }}static RSA *ssl_get_temporary_RSA_key(SSL *ssl, int isExport, int keyLen){  RSA *rsa = 0;  if (isExport) {    if (keyLen == 512)      return g_rsa_512;    else if (keyLen == 1024)      return g_rsa_1024;    else      return g_rsa_1024;  }  else    return g_rsa_1024;}static intssl_open(connection_t *conn, int fd){  int result;  SSL_CTX *ctx;  SSL *ssl;  SSL_CIPHER *cipher;  int algbits;  int retry = 10;  ctx = conn->context;  if (! ctx) {    ERR(("missing SSL context\n"));    return -1;  }    ssl = conn->sock;  if (! ssl) {    ssl = SSL_new(ctx);    conn->sock = ssl;  }  if (! ssl) {    closesocket(fd);    conn->fd = -1;    ERR(("can't allocate ssl\n"));    return -1;  }    SSL_set_fd(ssl, fd);  SSL_set_app_data(ssl, conn);  SSL_set_tmp_rsa_callback(ssl, ssl_get_temporary_RSA_key);  /* set non-blocking i/o */#ifndef WIN32  {    int flags;    flags = fcntl(fd, F_GETFL);    fcntl(fd, F_SETFL, O_NONBLOCK|flags);  }#endif  while (retry-- >= 0 && ! SSL_is_init_finished(ssl)) {    fd_set read_mask;    struct timeval timeout;        timeout.tv_sec = 30;    timeout.tv_usec = 0;        FD_ZERO(&read_mask);    FD_SET(fd, &read_mask);        result = select(fd + 1, &read_mask, 0, 0, &timeout);        if (result < 0 && (errno == EINTR || errno == EAGAIN))      continue;        if (result <= 0) {      ERR(("select timeout %d err:%d\n", result, errno));    }        if (result > 0) {#ifdef THREADS      result = SSL_accept(ssl);#else      pthread_mutex_lock(conn->ssl_lock);      result = SSL_accept(ssl);      pthread_mutex_unlock(conn->ssl_lock);#endif          }    if (result > 0) {    }    else if (SSL_get_error(ssl, result) == SSL_ERROR_WANT_READ)      continue;    else if (result < 0) {      ERR(("can't accept ssl %d response %d\n",           result, SSL_get_error(ssl, result)));      ERR_print_errors_fp(stderr);      conn->sock = 0;      conn->fd = -1;      ssl_safe_free(fd, ssl);      closesocket(fd);      return -1;    }  }    conn->fd = fd;  cipher = SSL_get_current_cipher(ssl);  if (cipher) {    conn->ssl_cipher = (void *) SSL_CIPHER_get_name(cipher);    conn->ssl_bits = SSL_CIPHER_get_bits(cipher, &algbits);  }    return 0;}static intssl_read(connection_t *conn, char *buf, int len){  fd_set read_mask;  struct timeval timeout;  int fd;  int ms;  SSL *ssl;  int result;  int retry = 100;  int ssl_error = 0;  int timeout_chunk = 5;  int timeout_count;  if (conn->fd < 0)    return -1;  if (! conn)    return -1;    fd = conn->fd;  ms = conn->timeout;  if (ms <= 0)    timeout_count = (30 + timeout_chunk - 1) / timeout_chunk;  else    timeout_count = (ms / 1000 + timeout_chunk - 1) / timeout_chunk;    if (timeout_count <= 0)    timeout_count = 1;    if (fd < 0)    return -1;    if (! conn->is_init) {    conn->is_init = 1;        if (ssl_open(conn, conn->fd) < 0) {      conn->ops->close(conn);      return -1;    }  }  ssl = conn->sock;  while (retry-- > 0) {    ssl_error = 0;        result = SSL_read(ssl, buf, len);    if (result >= 0)      return result;    else if ((ssl_error = SSL_get_error(ssl, result)) == SSL_ERROR_WANT_READ) {      /* wait for data */    }    else {      /*      fprintf(stderr, "disconnect from ssl error %d\n", ssl_error);      */      return DISCONNECT_EXN;    }    do {      FD_ZERO(&read_mask);      FD_SET(fd, &read_mask);      timeout.tv_sec = timeout_chunk;      timeout.tv_usec = 0;            result = select(fd + 1, &read_mask, 0, 0, &timeout);    } while (result < 0 && (errno == EINTR || errno == EAGAIN) && retry-- > 0);    if (result == 0 && --timeout_count <= 0)      return TIMEOUT_EXN;    else if (result < 0)      return exception_status(conn, errno);  }    return exception_status(conn, errno);}static intssl_write(connection_t *conn, char *buf, int len){  SSL *ssl = conn->sock;  fd_set write_mask;  struct timeval timeout;  int fd;  int ms;  int result;  int retry = 100;  if (! conn)    return -1;  if (conn->fd < 0)    return -1;    fd = conn->fd;    if (! conn->is_init) {    conn->is_init = 1;        if (ssl_open(conn, conn->fd) < 0) {      conn->ops->close(conn);      return -1;    }  }    ssl = conn->sock;    result = SSL_write(ssl, buf, len);  if (result > 0)    return result;  while (retry-- > 0) {    ms = conn->timeout;    FD_ZERO(&write_mask);    FD_SET(fd, &write_mask);    if (ms <= 0) {      timeout.tv_sec = 30;      timeout.tv_usec = 0;    } else {      timeout.tv_sec = ms / 1000;      timeout.tv_usec = ms % 1000 * 1000;    }      result = select(fd + 1, 0, &write_mask, 0, &timeout);          if (result > 0) {    }    else if (result == 0) {      conn->ops->close(conn);      return TIMEOUT_EXN;    }    else if (errno == EINTR || errno == EAGAIN)      continue;    else      return exception_status(conn, errno);    result = SSL_write(ssl, buf, len);    if (result >= 0)      return result;    else      continue;  }    return exception_status(conn, errno);}static intssl_close(connection_t *conn){  int fd;  SSL *ssl;  if (! conn)    return 0;  fd = conn->fd;  conn->fd = -1;  ssl = conn->sock;  conn->sock = 0;    ssl_safe_free(fd, ssl);  if (fd > 0)    closesocket(fd);  conn_close(conn);  return 0;}static voidssl_free(connection_t *conn){  SSL *ssl = conn->sock;  conn->sock = 0;  if (ssl) {    pthread_mutex_lock(conn->ssl_lock);    ssl_safe_free(-1, ssl);    pthread_mutex_unlock(conn->ssl_lock);  }  std_free(conn);}/** * Sets certificate chain stuff. */static intset_certificate_chain(SSL_CTX *ctx, ssl_config_t *config){  /* Not sure how this is supposed to work. */}intssl_create(server_socket_t *ss, ssl_config_t *config){  ss->ssl_config = config;  ss->verify_client = config->verify_client;  ss->context = ssl_create_context(config);  ss->accept = ssl_accept;  return 1;}static intssl_read_client_certificate(connection_t *conn, char *buffer, int length){  BIO *bio;  int n;  X509 *cert;    if (! conn)    return -1;    if (! conn->is_init) {    conn->is_init = 1;        if (ssl_open(conn, conn->fd) < 0) {      conn->ops->close(conn);      return -1;    }  }  cert = SSL_get_peer_certificate(conn->sock);  if (! cert)    return -1;  if ((bio = BIO_new(BIO_s_mem())) == NULL)    return -1;    PEM_write_bio_X509(bio, cert);  n = BIO_pending(bio);  if (n <= length)    n = BIO_read(bio, buffer, n);    BIO_free(bio);      return n;}

⌨️ 快捷键说明

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