ngx_event_openssl.c

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

C
1,975
字号
        return NGX_AGAIN;    }    c->ssl->no_wait_shutdown = 1;    c->ssl->no_send_shutdown = 1;    c->write->error = 1;    ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed");    return NGX_ERROR;}static voidngx_ssl_read_handler(ngx_event_t *rev){    ngx_connection_t  *c;    c = rev->data;    c->write->handler(c->write);}voidngx_ssl_free_buffer(ngx_connection_t *c){    if (c->ssl->buf && c->ssl->buf->start) {        if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) {            c->ssl->buf->start = NULL;        }    }}ngx_int_tngx_ssl_shutdown(ngx_connection_t *c){    int        n, sslerr, mode;    ngx_err_t  err;    if (c->timedout) {        mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;    } else {        mode = SSL_get_shutdown(c->ssl->connection);        if (c->ssl->no_wait_shutdown) {            mode |= SSL_RECEIVED_SHUTDOWN;        }        if (c->ssl->no_send_shutdown) {            mode |= SSL_SENT_SHUTDOWN;        }    }    SSL_set_shutdown(c->ssl->connection, mode);    ngx_ssl_clear_error(c->log);    n = SSL_shutdown(c->ssl->connection);    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);    sslerr = 0;    /* SSL_shutdown() never returns -1, on error it returns 0 */    if (n != 1 && ERR_peek_error()) {        sslerr = SSL_get_error(c->ssl->connection, n);        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,                       "SSL_get_error: %d", sslerr);    }    if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {        SSL_free(c->ssl->connection);        c->ssl = NULL;        return NGX_OK;    }    if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {        c->read->handler = ngx_ssl_shutdown_handler;        c->write->handler = ngx_ssl_shutdown_handler;        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 (sslerr == SSL_ERROR_WANT_READ) {            ngx_add_timer(c->read, 30000);        }        return NGX_AGAIN;    }    err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;    ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");    SSL_free(c->ssl->connection);    c->ssl = NULL;    return NGX_ERROR;}static voidngx_ssl_shutdown_handler(ngx_event_t *ev){    ngx_connection_t           *c;    ngx_connection_handler_pt   handler;    c = ev->data;    handler = c->ssl->handler;    if (ev->timedout) {        c->timedout = 1;    }    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler");    if (ngx_ssl_shutdown(c) == NGX_AGAIN) {        return;    }    handler(c);}static voidngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,    char *text){    int         n;    ngx_uint_t  level;    level = NGX_LOG_CRIT;    if (sslerr == SSL_ERROR_SYSCALL) {        if (err == NGX_ECONNRESET            || err == NGX_EPIPE            || err == NGX_ENOTCONN#if !(NGX_CRIT_ETIMEDOUT)            || err == NGX_ETIMEDOUT#endif            || err == NGX_ECONNREFUSED            || err == NGX_ENETDOWN            || err == NGX_ENETUNREACH            || err == NGX_EHOSTDOWN            || err == NGX_EHOSTUNREACH)        {            switch (c->log_error) {            case NGX_ERROR_IGNORE_ECONNRESET:            case NGX_ERROR_INFO:                level = NGX_LOG_INFO;                break;            case NGX_ERROR_ERR:                level = NGX_LOG_ERR;                break;            default:                break;            }        }    } else if (sslerr == SSL_ERROR_SSL) {        n = ERR_GET_REASON(ERR_peek_error());            /* handshake failures */        if (n == SSL_R_DIGEST_CHECK_FAILED            || n == SSL_R_NO_SHARED_CIPHER            || n == SSL_R_UNEXPECTED_MESSAGE            || n == SSL_R_WRONG_VERSION_NUMBER            || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC            || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */            || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE            || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC            || n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE            || n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE            || n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE            || n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE            || n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED            || n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED            || n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN            || n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER            || n == SSL_R_TLSV1_ALERT_UNKNOWN_CA)        {            switch (c->log_error) {            case NGX_ERROR_IGNORE_ECONNRESET:            case NGX_ERROR_INFO:                level = NGX_LOG_INFO;                break;            case NGX_ERROR_ERR:                level = NGX_LOG_ERR;                break;            default:                break;            }        }    }    ngx_ssl_error(level, c->log, err, text);}static voidngx_ssl_clear_error(ngx_log_t *log){    while (ERR_peek_error()) {        ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error");    }    ERR_clear_error();}void ngx_cdeclngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...){    u_long    n;    va_list   args;    u_char   *p, *last;    u_char    errstr[NGX_MAX_CONF_ERRSTR];    last = errstr + NGX_MAX_CONF_ERRSTR;    va_start(args, fmt);    p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args);    va_end(args);    p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);    for ( ;; ) {        n = ERR_get_error();        if (n == 0) {            break;        }        if (p >= last) {            continue;        }        *p++ = ' ';        ERR_error_string_n(n, (char *) p, last - p);        while (p < last && *p) {            p++;        }    }    ngx_log_error(level, log, err, "%s)", errstr);}ngx_int_tngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,    ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout){    long  cache_mode;    if (builtin_session_cache == NGX_SSL_NO_SCACHE) {        SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);        return NGX_OK;    }    cache_mode = SSL_SESS_CACHE_SERVER;    if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {        cache_mode |= SSL_SESS_CACHE_NO_INTERNAL;    }    SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode);    SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);    if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) {        if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {            SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);        }    }    SSL_CTX_set_timeout(ssl->ctx, timeout);    if (shm_zone) {        shm_zone->init = ngx_ssl_session_cache_init;        SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);        SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);        SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session);        if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone)            == 0)        {            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,                          "SSL_CTX_set_ex_data() failed");            return NGX_ERROR;        }    }    return NGX_OK;}static ngx_int_tngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data){    ngx_slab_pool_t          *shpool;    ngx_ssl_session_cache_t  *cache;    if (data) {        shm_zone->data = data;        return NGX_OK;    }    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;    cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));    if (cache == NULL) {        return NGX_ERROR;    }    ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel,                    ngx_ssl_session_rbtree_insert_value);    ngx_queue_init(&cache->expire_queue);    shm_zone->data = cache;    return NGX_OK;}/* * The length of the session id is 16 bytes for SSLv2 sessions and * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes. * It seems that the typical length of the external ASN1 representation * of a session is 118 or 119 bytes for SSLv3/TSLv1. * * Thus on 32-bit platforms we allocate separately an rbtree node, * a session id, and an ASN1 representation, they take accordingly * 64, 32, and 128 bytes. * * On 64-bit platforms we allocate separately an rbtree node + session_id, * and an ASN1 representation, they take accordingly 128 and 128 bytes. * * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, * so they are outside the code locked by shared pool mutex */static intngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess){    int                       len;    u_char                   *p, *id, *cached_sess;    uint32_t                  hash;    SSL_CTX                  *ssl_ctx;    ngx_shm_zone_t           *shm_zone;    ngx_connection_t         *c;    ngx_slab_pool_t          *shpool;    ngx_ssl_sess_id_t        *sess_id;    ngx_ssl_session_cache_t  *cache;    u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];    len = i2d_SSL_SESSION(sess, NULL);    /* do not cache too big session */    if (len > (int) NGX_SSL_MAX_SESSION_SIZE) {        return 0;    }    p = buf;    i2d_SSL_SESSION(sess, &p);    c = ngx_ssl_get_connection(ssl_conn);    ssl_ctx = SSL_get_SSL_CTX(ssl_conn);    shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index);    cache = shm_zone->data;    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;    ngx_shmtx_lock(&shpool->mutex);    /* drop one or two expired sessions */    ngx_ssl_expire_sessions(cache, shpool, 1);    cached_sess = ngx_slab_alloc_locked(shpool, len);    if (cached_sess == NULL) {        /* drop the oldest non-expired session and try once more */        ngx_ssl_expire_sessions(cache, shpool, 0);        cached_sess = ngx_slab_alloc_locked(shpool, len);        if (cached_sess == NULL) {            sess_id = NULL;            goto failed;        }    }    sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));    if (sess_id == NULL) {        goto failed;    }#if (NGX_PTR_SIZE == 8)    id = sess_id->sess_id;#else    id = ngx_slab_alloc_locked(shpool, sess->session_id_length);    if (id == NULL) {        goto failed;    }#endif    ngx_memcpy(cached_sess, buf, len);    ngx_memcpy(id, sess->session_id, sess->session_id_length);    hash = ngx_crc32_short(sess->session_id, sess->session_id_length);    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,                   "http ssl new session: %08XD:%d:%d",                   hash, sess->session_id_length, len);    sess_id->node.key = hash;    sess_id->node.data = (u_char) sess->session_id_length;    sess_id->id = id;    sess_id->len = len;    sess_id->session = cached_sess;    sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx);    ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue);    ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node);    ngx_shmtx_unlock(&shpool->mutex);    return 0;failed:    if (cached_sess) {        ngx_slab_free_locked(shpool, cached_sess);    }    if (sess_id) {        ngx_slab_free_locked(shpool, sess_id);    }    ngx_shmtx_unlock(&shpool->mutex);    ngx_log_error(NGX_LOG_ALERT, c->log, 0,                  "could not add new SSL session to the session cache");    return 0;}static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len,    int *copy){#if OPENSSL_VERSION_NUMBER >= 0x0090707fL    const#endif    u_char                   *p;    uint32_t                  hash;    ngx_int_t                 rc;    ngx_shm_zone_t           *shm_zone;

⌨️ 快捷键说明

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