ngx_event_openssl.c

来自「Nginx是一个高性能的HTTP和反向代理服务器」· C语言 代码 · 共 1,975 行 · 第 1/4 页

C
1,975
字号
/* * Copyright (C) Igor Sysoev */#include <ngx_config.h>#include <ngx_core.h>#include <ngx_event.h>typedef struct {    ngx_str_t  engine;} ngx_openssl_conf_t;static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);static void ngx_ssl_handshake_handler(ngx_event_t *ev);static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);static void ngx_ssl_write_handler(ngx_event_t *wev);static void ngx_ssl_read_handler(ngx_event_t *rev);static void ngx_ssl_shutdown_handler(ngx_event_t *ev);static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,    ngx_err_t err, char *text);static void ngx_ssl_clear_error(ngx_log_t *log);static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone,    void *data);static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,    ngx_ssl_session_t *sess);static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,    u_char *id, int len, int *copy);static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,    ngx_slab_pool_t *shpool, ngx_uint_t n);static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);static void ngx_openssl_exit(ngx_cycle_t *cycle);#if !(NGX_SSL_ENGINE)static char *ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd,     void *conf);#endifstatic ngx_command_t  ngx_openssl_commands[] = {    { ngx_string("ssl_engine"),      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,#if (NGX_SSL_ENGINE)      ngx_conf_set_str_slot,#else      ngx_openssl_noengine,#endif      0,      offsetof(ngx_openssl_conf_t, engine),      NULL },      ngx_null_command};static ngx_core_module_t  ngx_openssl_module_ctx = {    ngx_string("openssl"),    ngx_openssl_create_conf,    ngx_openssl_init_conf};ngx_module_t  ngx_openssl_module = {    NGX_MODULE_V1,    &ngx_openssl_module_ctx,               /* module context */    ngx_openssl_commands,                  /* module directives */    NGX_CORE_MODULE,                       /* module type */    NULL,                                  /* init master */    NULL,                                  /* init module */    NULL,                                  /* init process */    NULL,                                  /* init thread */    NULL,                                  /* exit thread */    NULL,                                  /* exit process */    ngx_openssl_exit,                      /* exit master */    NGX_MODULE_V1_PADDING};static long  ngx_ssl_protocols[] = {    SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1,    SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1,    SSL_OP_NO_SSLv2|SSL_OP_NO_TLSv1,    SSL_OP_NO_TLSv1,    SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3,    SSL_OP_NO_SSLv3,    SSL_OP_NO_SSLv2,    0,};int  ngx_ssl_connection_index;int  ngx_ssl_server_conf_index;int  ngx_ssl_session_cache_index;ngx_int_tngx_ssl_init(ngx_log_t *log){#if OPENSSL_VERSION_NUMBER >= 0x00907000    OPENSSL_config(NULL);#endif    SSL_library_init();    SSL_load_error_strings();#if (NGX_SSL_ENGINE)    ENGINE_load_builtin_engines();#endif    ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);    if (ngx_ssl_connection_index == -1) {        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");        return NGX_ERROR;    }    ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,                                                         NULL);    if (ngx_ssl_server_conf_index == -1) {        ngx_ssl_error(NGX_LOG_ALERT, log, 0,                      "SSL_CTX_get_ex_new_index() failed");        return NGX_ERROR;    }    ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,                                                           NULL);    if (ngx_ssl_session_cache_index == -1) {        ngx_ssl_error(NGX_LOG_ALERT, log, 0,                      "SSL_CTX_get_ex_new_index() failed");        return NGX_ERROR;    }    return NGX_OK;}ngx_int_tngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data){    ssl->ctx = SSL_CTX_new(SSLv23_method());    if (ssl->ctx == NULL) {        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");        return NGX_ERROR;    }    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,                      "SSL_CTX_set_ex_data() failed");        return NGX_ERROR;    }    /* client side options */    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);    SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);    /* server side options */    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);    SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);    /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */    SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);    SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);    SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS    SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);#endif    if (ngx_ssl_protocols[protocols >> 1] != 0) {        SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]);    }    /*     * we need this option because in ngx_ssl_send_chain()     * we may switch to a buffered write and may copy leftover part of     * previously unbuffered data to our internal buffer     */    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);    SSL_CTX_set_read_ahead(ssl->ctx, 1);    return NGX_OK;}ngx_int_tngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,    ngx_str_t *key){    if (ngx_conf_full_name(cf->cycle, cert, 1) == NGX_ERROR) {        return NGX_ERROR;    }    if (SSL_CTX_use_certificate_chain_file(ssl->ctx, (char *) cert->data)        == 0)    {        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,                      "SSL_CTX_use_certificate_chain_file(\"%s\") failed",                      cert->data);        return NGX_ERROR;    }    if (ngx_conf_full_name(cf->cycle, key, 1) == NGX_ERROR) {        return NGX_ERROR;    }    if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,                                    SSL_FILETYPE_PEM)        == 0)    {        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);        return NGX_ERROR;    }    return NGX_OK;}ngx_int_tngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,    ngx_int_t depth){    STACK_OF(X509_NAME)  *list;    SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_http_ssl_verify_callback);    SSL_CTX_set_verify_depth(ssl->ctx, depth);    if (cert->len == 0) {        return NGX_OK;    }    if (ngx_conf_full_name(cf->cycle, cert, 1) == NGX_ERROR) {        return NGX_ERROR;    }    if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)        == 0)    {        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,                      "SSL_CTX_load_verify_locations(\"%s\") failed",                      cert->data);        return NGX_ERROR;    }    list = SSL_load_client_CA_file((char *) cert->data);    if (list == NULL) {        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,                      "SSL_load_client_CA_file(\"%s\") failed", cert->data);        return NGX_ERROR;    }    /*     * before 0.9.7h and 0.9.8 SSL_load_client_CA_file()     * always leaved an error in the error queue     */    ERR_clear_error();    SSL_CTX_set_client_CA_list(ssl->ctx, list);    return NGX_OK;}static intngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store){#if (NGX_DEBUG)    char              *subject, *issuer;    int                err, depth;    X509              *cert;    X509_NAME         *sname, *iname;    ngx_connection_t  *c;    ngx_ssl_conn_t    *ssl_conn;    ssl_conn = X509_STORE_CTX_get_ex_data(x509_store,                                          SSL_get_ex_data_X509_STORE_CTX_idx());    c = ngx_ssl_get_connection(ssl_conn);    cert = X509_STORE_CTX_get_current_cert(x509_store);    err = X509_STORE_CTX_get_error(x509_store);    depth = X509_STORE_CTX_get_error_depth(x509_store);    sname = X509_get_subject_name(cert);    subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)";    iname = X509_get_issuer_name(cert);    issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";    ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,                   "verify:%d, error:%d, depth:%d, "                   "subject:\"%s\",issuer: \"%s\"",                   ok, err, depth, subject, issuer);    if (sname) {        OPENSSL_free(subject);    }    if (iname) {        OPENSSL_free(issuer);    }#endif    return 1;}ngx_int_tngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl){    RSA  *key;    if (SSL_CTX_need_tmp_RSA(ssl->ctx) == 0) {        return NGX_OK;    }    key = RSA_generate_key(512, RSA_F4, NULL, NULL);    if (key) {        SSL_CTX_set_tmp_rsa(ssl->ctx, key);        RSA_free(key);        return NGX_OK;    }    ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "RSA_generate_key(512) failed");    return NGX_ERROR;}ngx_int_tngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags){    ngx_ssl_connection_t  *sc;    sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t));    if (sc == NULL) {        return NGX_ERROR;    }    sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);    sc->connection = SSL_new(ssl->ctx);    if (sc->connection == NULL) {        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");        return NGX_ERROR;    }    if (SSL_set_fd(sc->connection, c->fd) == 0) {        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");        return NGX_ERROR;    }    if (flags & NGX_SSL_CLIENT) {        SSL_set_connect_state(sc->connection);    } else {        SSL_set_accept_state(sc->connection);    }    if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) {        ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");        return NGX_ERROR;    }    c->ssl = sc;    return NGX_OK;}ngx_int_tngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session){    if (session) {        if (SSL_set_session(c->ssl->connection, session) == 0) {            ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_session() failed");            return NGX_ERROR;        }    }    return NGX_OK;}ngx_int_tngx_ssl_handshake(ngx_connection_t *c){    int        n, sslerr;    ngx_err_t  err;    ngx_ssl_clear_error(c->log);    n = SSL_do_handshake(c->ssl->connection);    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);    if (n == 1) {        if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {            return NGX_ERROR;        }        if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {            return NGX_ERROR;        }#if (NGX_DEBUG)        {        char         buf[129], *s, *d;        SSL_CIPHER  *cipher;        cipher = SSL_get_current_cipher(c->ssl->connection);        if (cipher) {            SSL_CIPHER_description(cipher, &buf[1], 128);            for (s = &buf[1], d = buf; *s; s++) {                if (*s == ' ' && *d == ' ') {                    continue;                }                if (*s == LF || *s == CR) {                    continue;                }                *++d = *s;            }            if (*d != ' ') {                d++;            }            *d = '\0';            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,                           "SSL: %s, cipher: \"%s\"",                           SSL_get_version(c->ssl->connection), &buf[1]);            if (SSL_session_reused(c->ssl->connection)) {                ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,                               "SSL reused session");            }        } else {            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,                           "SSL no shared ciphers");        }        }#endif        c->ssl->handshaked = 1;        c->recv = ngx_ssl_recv;        c->send = ngx_ssl_write;        c->recv_chain = ngx_ssl_recv_chain;        c->send_chain = ngx_ssl_send_chain;        return NGX_OK;    }    sslerr = SSL_get_error(c->ssl->connection, n);    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);    if (sslerr == SSL_ERROR_WANT_READ) {        c->read->ready = 0;        c->read->handler = ngx_ssl_handshake_handler;        c->write->handler = ngx_ssl_handshake_handler;

⌨️ 快捷键说明

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