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

📄 ssl_engine_io.c

📁 linux网络服务器工具
💻 C
📖 第 1 页 / 共 5 页
字号:
    /*     * Check for failed client authentication     */    verify_result = SSL_get_verify_result(filter_ctx->pssl);    if ((verify_result != X509_V_OK) ||        sslconn->verify_error)    {        if (ssl_verify_error_is_optional(verify_result) &&            (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))        {            /* leaving this log message as an error for the moment,             * according to the mod_ssl docs:             * "level optional_no_ca is actually against the idea             *  of authentication (but can be used to establish             * SSL test pages, etc.)"             * optional_no_ca doesn't appear to work as advertised             * in 1.x             */            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,                          "SSL client authentication failed, "                          "accepting certificate based on "                          "\"SSLVerifyClient optional_no_ca\" "                          "configuration");            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);        }        else {            const char *error = sslconn->verify_error ?                sslconn->verify_error :                X509_verify_cert_error_string(verify_result);            ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,                         "SSL client authentication failed: %s",                         error ? error : "unknown");            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);            return ssl_filter_io_shutdown(filter_ctx, c, 1);        }    }    /*     * Remember the peer certificate's DN     */    if ((cert = SSL_get_peer_certificate(filter_ctx->pssl))) {        if (sslconn->client_cert) {            X509_free(sslconn->client_cert);        }        sslconn->client_cert = cert;        sslconn->client_dn = NULL;    }    /*     * Make really sure that when a peer certificate     * is required we really got one... (be paranoid)     */    if ((sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE) &&        !sslconn->client_cert)    {        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,                      "No acceptable peer certificate available");        return ssl_filter_io_shutdown(filter_ctx, c, 1);    }    return APR_SUCCESS;}#define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"#define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1"#define CONNECTION_HEADER "Connection: Upgrade"static apr_status_t ssl_io_filter_Upgrade(ap_filter_t *f,                                          apr_bucket_brigade *bb){    const char *upgrade;    apr_bucket_brigade *upgradebb;    request_rec *r = f->r;    SSLConnRec *sslconn;    apr_status_t rv;    apr_bucket *b;    SSL *ssl;    /* Just remove the filter, if it doesn't work the first time, it won't     * work at all for this request.     */    ap_remove_output_filter(f);    /* No need to ensure that this is a server with optional SSL, the filter     * is only inserted if that is true.     */    upgrade = apr_table_get(r->headers_in, "Upgrade");    if (upgrade == NULL        || strcmp(ap_getword(r->pool, &upgrade, ','), "TLS/1.0")) {        /* "Upgrade: TLS/1.0, ..." header not found, don't do Upgrade */        return ap_pass_brigade(f->next, bb);    }    apr_table_unset(r->headers_out, "Upgrade");    /* Send the interim 101 response. */    upgradebb = apr_brigade_create(r->pool, f->c->bucket_alloc);    ap_fputstrs(f->next, upgradebb, SWITCH_STATUS_LINE, CRLF,                UPGRADE_HEADER, CRLF, CONNECTION_HEADER, CRLF, CRLF, NULL);    b = apr_bucket_flush_create(f->c->bucket_alloc);    APR_BRIGADE_INSERT_TAIL(upgradebb, b);    rv = ap_pass_brigade(f->next, upgradebb);    if (rv) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,                      "could not send interim 101 Upgrade response");        return AP_FILTER_ERROR;    }    ssl_init_ssl_connection(f->c);    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,                  "Awaiting re-negotiation handshake");    sslconn = myConnConfig(f->c);    ssl = sslconn->ssl;    /* XXX: Should replace SSL_set_state with SSL_renegotiate(ssl);     * However, this causes failures in perl-framework currently,     * perhaps pre-test if we have already negotiated?     */    SSL_set_accept_state(ssl);    SSL_do_handshake(ssl);    if (SSL_get_state(ssl) != SSL_ST_OK) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                      "TLS Upgrade handshake failed: "                      "Not accepted by client!?");        return AP_FILTER_ERROR;    }    /* Now that we have initialized the ssl connection which added the ssl_io_filter,       pass the brigade off to the connection based output filters so that the       request can complete encrypted */    return ap_pass_brigade(f->c->output_filters, bb);}static apr_status_t ssl_io_filter_input(ap_filter_t *f,                                        apr_bucket_brigade *bb,                                        ap_input_mode_t mode,                                        apr_read_type_e block,                                        apr_off_t readbytes){    apr_status_t status;    bio_filter_in_ctx_t *inctx = f->ctx;    apr_size_t len = sizeof(inctx->buffer);    int is_init = (mode == AP_MODE_INIT);    if (f->c->aborted) {        /* XXX: Ok, if we aborted, we ARE at the EOS.  We also have         * aborted.  This 'double protection' is probably redundant,         * but also effective against just about anything.         */        apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(bb, bucket);        return APR_ECONNABORTED;    }    if (!inctx->ssl) {        return ap_get_brigade(f->next, bb, mode, block, readbytes);    }    /* XXX: we don't currently support anything other than these modes. */    if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE &&        mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) {        return APR_ENOTIMPL;    }    inctx->mode = mode;    inctx->block = block;    /* XXX: we could actually move ssl_io_filter_connect to an     * ap_hook_process_connection but would still need to call it for     * AP_MODE_INIT for protocols that may upgrade the connection     * rather than have SSLEngine On configured.     */    if ((status = ssl_io_filter_connect(inctx->filter_ctx)) != APR_SUCCESS) {        return ssl_io_filter_error(f, bb, status);    }    if (is_init) {        /* protocol module needs to handshake before sending         * data to client (e.g. NNTP or FTP)         */        return APR_SUCCESS;    }    if (inctx->mode == AP_MODE_READBYTES ||        inctx->mode == AP_MODE_SPECULATIVE) {        /* Protected from truncation, readbytes < MAX_SIZE_T         * FIXME: No, it's *not* protected.  -- jre */        if (readbytes < len) {            len = (apr_size_t)readbytes;        }        status = ssl_io_input_read(inctx, inctx->buffer, &len);    }    else if (inctx->mode == AP_MODE_GETLINE) {        status = ssl_io_input_getline(inctx, inctx->buffer, &len);    }    else {        /* We have no idea what you are talking about, so return an error. */        return APR_ENOTIMPL;    }    if (status != APR_SUCCESS) {        return ssl_io_filter_error(f, bb, status);    }    /* Create a transient bucket out of the decrypted data. */    if (len > 0) {        apr_bucket *bucket =            apr_bucket_transient_create(inctx->buffer, len, f->c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(bb, bucket);    }    return APR_SUCCESS;}static apr_status_t ssl_io_filter_output(ap_filter_t *f,                                         apr_bucket_brigade *bb){    apr_status_t status = APR_SUCCESS;    ssl_filter_ctx_t *filter_ctx = f->ctx;    bio_filter_in_ctx_t *inctx;    bio_filter_out_ctx_t *outctx;    apr_read_type_e rblock = APR_NONBLOCK_READ;    if (f->c->aborted) {        apr_brigade_cleanup(bb);        return APR_ECONNABORTED;    }    if (!filter_ctx->pssl) {        /* ssl_filter_io_shutdown was called */        return ap_pass_brigade(f->next, bb);    }    inctx = (bio_filter_in_ctx_t *)filter_ctx->pbioRead->ptr;    outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr;    /* When we are the writer, we must initialize the inctx     * mode so that we block for any required ssl input, because     * output filtering is always nonblocking.     */    inctx->mode = AP_MODE_READBYTES;    inctx->block = APR_BLOCK_READ;    if ((status = ssl_io_filter_connect(filter_ctx)) != APR_SUCCESS) {        return ssl_io_filter_error(f, bb, status);    }    while (!APR_BRIGADE_EMPTY(bb)) {        apr_bucket *bucket = APR_BRIGADE_FIRST(bb);        /* If it is a flush or EOS, we need to pass this down.         * These types do not require translation by OpenSSL.         */        if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {            if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) {                status = outctx->rc;                break;            }            if (APR_BUCKET_IS_EOS(bucket)) {                /*                 * By definition, nothing can come after EOS.                 * which also means we can pass the rest of this brigade                 * without creating a new one since it only contains the                 * EOS bucket.                 */                if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {                    return status;                }                break;            }            else {                /* bio_filter_out_flush() already passed down a flush bucket                 * if there was any data to be flushed.                 */                apr_bucket_delete(bucket);            }        }        else if (AP_BUCKET_IS_EOC(bucket)) {            /* The special "EOC" bucket means a shutdown is needed;             * - turn off buffering in bio_filter_out_write             * - issue the SSL_shutdown             */            filter_ctx->nobuffer = 1;            status = ssl_filter_io_shutdown(filter_ctx, f->c, 0);            if (status != APR_SUCCESS) {                ap_log_cerror(APLOG_MARK, APLOG_INFO, status, f->c,                              "SSL filter error shutting down I/O");            }            if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {                return status;            }            break;        }        else {            /* filter output */            const char *data;            apr_size_t len;            status = apr_bucket_read(bucket, &data, &len, rblock);            if (APR_STATUS_IS_EAGAIN(status)) {                /* No data available: flush... */                if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) {                    status = outctx->rc;                    break;                }                rblock = APR_BLOCK_READ;                continue; /* and try again with a blocking read. */            }            rblock = APR_NONBLOCK_READ;            if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {                break;            }            status = ssl_filter_write(f, data, len);            apr_bucket_delete(bucket);            if (status != APR_SUCCESS) {                break;            }        }    }    return status;}/* 128K maximum buffer size by default. */#ifndef SSL_MAX_IO_BUFFER#define SSL_MAX_IO_BUFFER (128 * 1024)#endifstruct modssl_buffer_ctx {    apr_bucket_brigade *bb;    apr_pool_t *pool;};int ssl_io_buffer_fill(request_rec *r){    conn_rec *c = r->connection;    struct modssl_buffer_ctx *ctx;    apr_bucket_brigade *tempb;    apr_off_t total = 0; /* total length buffered */    int eos = 0; /* non-zero once EOS is seen */    /* Create the context which will be passed to the input filter;     * containing a setaside pool and a brigade which constrain the     * lifetime of the buffered data. */    ctx = apr_palloc(r->pool, sizeof *ctx);    apr_pool_create(&ctx->pool, r->pool);

⌨️ 快捷键说明

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