示例#1
0
void ssl_init_Engine(server_rec *s, apr_pool_t *p)
{
    SSLModConfigRec *mc = myModConfig(s);
    ENGINE *e;

    if (mc->szCryptoDevice) {
        if (!(e = ENGINE_by_id(mc->szCryptoDevice))) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                         "Init: Failed to load Crypto Device API `%s'",
                         mc->szCryptoDevice);
            ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
            ssl_die();
        }

        if (strEQ(mc->szCryptoDevice, "chil")) {
            ENGINE_ctrl(e, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
        }

        if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                         "Init: Failed to enable Crypto Device API `%s'",
                         mc->szCryptoDevice);
            ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
            ssl_die();
        }
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 
                     "Init: loaded Crypto Device API `%s'", 
                     mc->szCryptoDevice);

        ENGINE_free(e);
    }
}
示例#2
0
OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri,
                                            apr_interval_time_t timeout,
                                            OCSP_REQUEST *request,
                                            conn_rec *c, apr_pool_t *p)
{
    OCSP_RESPONSE *response = NULL;
    apr_socket_t *sd;
    BIO *bio;

    bio = serialize_request(request, uri);
    if (bio == NULL) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01989)
                      "could not serialize OCSP request");
        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
        return NULL;
    }

    sd = send_request(bio, uri, timeout, c, p);
    if (sd == NULL) {
        /* Errors already logged. */
        BIO_free(bio);
        return NULL;
    }

    /* Clear the BIO contents, ready for the response. */
    (void)BIO_reset(bio);

    response = read_response(sd, bio, c, p);

    apr_socket_close(sd);
    BIO_free(bio);

    return response;
}
示例#3
0
STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7)
{
    PKCS7 *p7;
    STACK_OF(X509) *certs = NULL;
    FILE *f;

    f = fopen(pkcs7, "r");
    if (!f) {
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02212) "Can't open %s", pkcs7);
        ssl_die(s);
    }

    p7 = PEM_read_PKCS7(f, NULL, NULL, NULL);
    if (!p7) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02274)
                     "Can't read PKCS7 object %s", pkcs7);
        ssl_log_ssl_error(SSLLOG_MARK, APLOG_CRIT, s);
        exit(1);
    }

    switch (OBJ_obj2nid(p7->type)) {
    case NID_pkcs7_signed:
        certs = p7->d.sign->cert;
        p7->d.sign->cert = NULL;
        PKCS7_free(p7);
        break;

    case NID_pkcs7_signedAndEnveloped:
        certs = p7->d.signed_and_enveloped->cert;
        p7->d.signed_and_enveloped->cert = NULL;
        PKCS7_free(p7);
        break;

    default:
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02213)
                     "Don't understand PKCS7 file %s", pkcs7);
        ssl_die(s);
    }

    if (!certs) {
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02214)
                     "No certificates in %s", pkcs7);
        ssl_die(s);
    }

    fclose(f);

    return certs;
}
示例#4
0
/* Create an OCSP request for the given certificate; returning the
 * certificate ID in *certid and *issuer on success.  Returns the
 * request object on success, or NULL on error. */
static OCSP_REQUEST *create_request(X509_STORE_CTX *ctx, X509 *cert,
                                    OCSP_CERTID **certid,
                                    server_rec *s, apr_pool_t *p,
                                    SSLSrvConfigRec *sc)
{
    OCSP_REQUEST *req = OCSP_REQUEST_new();

    *certid = OCSP_cert_to_id(NULL, cert, ctx->current_issuer);
    if (!*certid || !OCSP_request_add0_id(req, *certid)) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01921)
                     "could not retrieve certificate id");
        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
        return NULL;
    }

    if (sc->server->ocsp_use_request_nonce != FALSE) {
        OCSP_request_add1_nonce(req, 0, -1);
    }

    return req;
}
int ssl_init_ssl_connection(conn_rec *c)
{
    SSLSrvConfigRec *sc;
    SSL *ssl;
    SSLConnRec *sslconn = myConnConfig(c);
    char *vhost_md5;
    modssl_ctx_t *mctx;
    server_rec *server;

    if (!sslconn) {
        sslconn = ssl_init_connection_ctx(c);
    }
    server = sslconn->server;
    sc = mySrvConfig(server);

    /*
     * Seed the Pseudo Random Number Generator (PRNG)
     */
    ssl_rand_seed(server, c->pool, SSL_RSCTX_CONNECT, "");

    mctx = sslconn->is_proxy ? sc->proxy : sc->server;

    /*
     * Create a new SSL connection with the configured server SSL context and
     * attach this to the socket. Additionally we register this attachment
     * so we can detach later.
     */
    if (!(ssl = SSL_new(mctx->ssl_ctx))) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
                      "Unable to create a new SSL connection from the SSL "
                      "context");
        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);

        c->aborted = 1;

        return DECLINED; /* XXX */
    }

    vhost_md5 = ap_md5_binary(c->pool, (unsigned char *)sc->vhost_id,
                              sc->vhost_id_len);

    if (!SSL_set_session_id_context(ssl, (unsigned char *)vhost_md5,
                                    APR_MD5_DIGESTSIZE*2))
    {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
                      "Unable to set session id context to `%s'", vhost_md5);
        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);

        c->aborted = 1;

        return DECLINED; /* XXX */
    }

    SSL_set_app_data(ssl, c);
    SSL_set_app_data2(ssl, NULL); /* will be request_rec */

    sslconn->ssl = ssl;

    /*
     *  Configure callbacks for SSL connection
     */
    SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA);
    SSL_set_tmp_dh_callback(ssl,  ssl_callback_TmpDH);

    SSL_set_verify_result(ssl, X509_V_OK);

    ssl_io_filter_init(c, ssl);

    return APR_SUCCESS;
}
示例#6
0
static void ssl_init_ctx_verify(server_rec *s,
                                apr_pool_t *p,
                                apr_pool_t *ptemp,
                                modssl_ctx_t *mctx)
{
    SSL_CTX *ctx = mctx->ssl_ctx;

    int verify = SSL_VERIFY_NONE;
    STACK_OF(X509_NAME) *ca_list;

    if (mctx->auth.verify_mode == SSL_CVERIFY_UNSET) {
        mctx->auth.verify_mode = SSL_CVERIFY_NONE;
    }

    if (mctx->auth.verify_depth == UNSET) {
        mctx->auth.verify_depth = 1;
    }

    /*
     *  Configure callbacks for SSL context
     */
    if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) {
        verify |= SSL_VERIFY_PEER_STRICT;
    }

    if ((mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL) ||
        (mctx->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
    {
        verify |= SSL_VERIFY_PEER;
    }

    SSL_CTX_set_verify(ctx, verify, ssl_callback_SSLVerify);

    /*
     * Configure Client Authentication details
     */
    if (mctx->auth.ca_cert_file || mctx->auth.ca_cert_path) {
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
                     "Configuring client authentication");

        if (!SSL_CTX_load_verify_locations(ctx,
                         MODSSL_PCHAR_CAST mctx->auth.ca_cert_file,
                         MODSSL_PCHAR_CAST mctx->auth.ca_cert_path))
        {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                    "Unable to configure verify locations "
                    "for client authentication");
            ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
            ssl_die();
        }

        if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) {
            ca_list = ssl_init_FindCAList(s, ptemp,
                                          mctx->pks->ca_name_file,
                                          mctx->pks->ca_name_path);
        } else
            ca_list = ssl_init_FindCAList(s, ptemp,
                                          mctx->auth.ca_cert_file,
                                          mctx->auth.ca_cert_path);
        if (!ca_list) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
                    "Unable to determine list of acceptable "
                    "CA certificates for client authentication");
            ssl_die();
        }

        SSL_CTX_set_client_CA_list(ctx, (STACK *)ca_list);
    }

    /*
     * Give a warning when no CAs were configured but client authentication
     * should take place. This cannot work.
     */
    if (mctx->auth.verify_mode == SSL_CVERIFY_REQUIRE) {
        ca_list = (STACK_OF(X509_NAME) *)SSL_CTX_get_client_CA_list(ctx);

        if (sk_X509_NAME_num(ca_list) == 0) {
            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
                         "Init: Oops, you want to request client "
                         "authentication, but no CAs are known for "
                         "verification!?  [Hint: SSLCACertificate*]");
        }
    }
/* Read the OCSP response from the socket 'sd', using temporary memory
 * BIO 'bio', and return the decoded OCSP response object, or NULL on
 * error. */
static OCSP_RESPONSE *read_response(apr_socket_t *sd, BIO *bio, conn_rec *c,
                                    apr_pool_t *p)
{
    apr_bucket_brigade *bb, *tmpbb;
    OCSP_RESPONSE *response;
    char *line;
    apr_size_t count;
    apr_int64_t code;

    /* Using brigades for response parsing is much simpler than using
     * apr_socket_* directly. */
    bb = apr_brigade_create(p, c->bucket_alloc);
    tmpbb = apr_brigade_create(p, c->bucket_alloc);
    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_socket_create(sd, c->bucket_alloc));

    line = get_line(tmpbb, bb, c, p);
    if (!line || strncmp(line, "HTTP/", 5)
        || (line = ap_strchr(line, ' ')) == NULL
        || (code = apr_atoi64(++line)) < 200 || code > 299) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01980)
                      "bad response from OCSP server: %s",
                      line ? line : "(none)");
        return NULL;
    }

    /* Read till end of headers; don't have to even bother parsing the
     * Content-Length since the server is obliged to close the
     * connection after the response anyway for HTTP/1.0. */
    count = 0;
    while ((line = get_line(tmpbb, bb, c, p)) != NULL && line[0]
           && ++count < MAX_HEADERS) {
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01981)
                      "OCSP response header: %s", line);
    }

    if (count == MAX_HEADERS) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01982)
                      "could not read response headers from OCSP server, "
                      "exceeded maximum count (%u)", MAX_HEADERS);
        return NULL;
    }
    else if (!line) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01983)
                      "could not read response header from OCSP server");
        return NULL;
    }

    /* Read the response body into the memory BIO. */
    count = 0;
    while (!APR_BRIGADE_EMPTY(bb)) {
        const char *data;
        apr_size_t len;
        apr_status_t rv;
        apr_bucket *e = APR_BRIGADE_FIRST(bb);

        rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
        if (rv == APR_EOF) {
            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01984)
                          "OCSP response: got EOF");
            break;
        }
        if (rv != APR_SUCCESS) {
            ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01985)
                          "error reading response from OCSP server");
            return NULL;
        }
        if (len == 0) {
            /* Ignore zero-length buckets (possible side-effect of
             * line splitting). */
            apr_bucket_delete(e);
            continue;
        }
        count += len;
        if (count > MAX_CONTENT) {
            ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01986)
                          "OCSP response size exceeds %u byte limit",
                          MAX_CONTENT);
            return NULL;
        }
        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01987)
                      "OCSP response: got %" APR_SIZE_T_FMT
                      " bytes, %" APR_SIZE_T_FMT " total", len, count);

        BIO_write(bio, data, (int)len);
        apr_bucket_delete(e);
    }

    apr_brigade_destroy(bb);
    apr_brigade_destroy(tmpbb);

    /* Finally decode the OCSP response from what's stored in the
     * bio. */
    response = d2i_OCSP_RESPONSE_bio(bio, NULL);
    if (response == NULL) {
        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01988)
                      "failed to decode OCSP response data");
        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
    }

    return response;
}
示例#8
0
/* Verify the OCSP status of given certificate.  Returns
 * V_OCSP_CERTSTATUS_* result code. */
static int verify_ocsp_status(X509 *cert, X509_STORE_CTX *ctx, conn_rec *c,
                              SSLSrvConfigRec *sc, server_rec *s,
                              apr_pool_t *pool)
{
    int rc = V_OCSP_CERTSTATUS_GOOD;
    OCSP_RESPONSE *response = NULL;
    OCSP_BASICRESP *basicResponse = NULL;
    OCSP_REQUEST *request = NULL;
    OCSP_CERTID *certID = NULL;
    apr_uri_t *ruri;

    ruri = determine_responder_uri(sc, cert, c, pool);
    if (!ruri) {
        return V_OCSP_CERTSTATUS_UNKNOWN;
    }

    request = create_request(ctx, cert, &certID, s, pool, sc);
    if (request) {
        apr_interval_time_t to = sc->server->ocsp_responder_timeout == UNSET ?
                                 apr_time_from_sec(DEFAULT_OCSP_TIMEOUT) :
                                 sc->server->ocsp_responder_timeout;
        response = modssl_dispatch_ocsp_request(ruri, to, request, c, pool);
    }

    if (!request || !response) {
        rc = V_OCSP_CERTSTATUS_UNKNOWN;
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        int r = OCSP_response_status(response);

        if (r != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01922)
                         "OCSP response not successful: %d", rc);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        basicResponse = OCSP_response_get1_basic(response);
        if (!basicResponse) {
            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01923)
                          "could not retrieve OCSP basic response");
            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD &&
            sc->server->ocsp_use_request_nonce != FALSE &&
            OCSP_check_nonce(request, basicResponse) != 1) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01924)
                    "Bad OCSP responder answer (bad nonce)");
        rc = V_OCSP_CERTSTATUS_UNKNOWN;
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        /* TODO: allow flags configuration. */
        if (OCSP_basic_verify(basicResponse, NULL, ctx->ctx, 0) != 1) {
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01925)
                        "failed to verify the OCSP response");
            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
    }

    if (rc == V_OCSP_CERTSTATUS_GOOD) {
        int reason = -1, status;
        ASN1_GENERALIZEDTIME *thisup = NULL, *nextup = NULL;

        rc = OCSP_resp_find_status(basicResponse, certID, &status,
                                   &reason, NULL, &thisup, &nextup);
        if (rc != 1) {
            ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02272)
                            "failed to retrieve OCSP response status");
            ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
            rc = V_OCSP_CERTSTATUS_UNKNOWN;
        }
        else {
            rc = status;
        }

        /* Check whether the response is inside the defined validity
         * period; otherwise fail.  */
        if (rc != V_OCSP_CERTSTATUS_UNKNOWN) {
            long resptime_skew = sc->server->ocsp_resptime_skew == UNSET ?
                                 DEFAULT_OCSP_MAX_SKEW : sc->server->ocsp_resptime_skew;
            /* oscp_resp_maxage can be passed verbatim - UNSET (-1) means
             * that responses can be of any age as long as nextup is in the
             * future. */
            int vrc  = OCSP_check_validity(thisup, nextup, resptime_skew,
                                           sc->server->ocsp_resp_maxage);
            if (vrc != 1) {
                ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02273)
                                "OCSP response outside validity period");
                ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
                rc = V_OCSP_CERTSTATUS_UNKNOWN;
            }
        }

        {
            int level =
                (status == V_OCSP_CERTSTATUS_GOOD) ? APLOG_INFO : APLOG_ERR;
            const char *result =
                status == V_OCSP_CERTSTATUS_GOOD ? "good" :
                (status == V_OCSP_CERTSTATUS_REVOKED ? "revoked" : "unknown");

            ssl_log_cxerror(SSLLOG_MARK, level, 0, c, cert,
                            "OCSP validation completed, "
                            "certificate status: %s (%d, %d)",
                            result, status, reason);
        }
    }

    if (request) OCSP_REQUEST_free(request);
    if (response) OCSP_RESPONSE_free(response);
    if (basicResponse) OCSP_BASICRESP_free(basicResponse);
    /* certID is freed when the request is freed */

    return rc;
}