Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 681363 Details for
Bug 899392
RHEL 4 OCSP support in EWS
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
httpd-2.2.14-sslocsp.patch
httpd-2.2.14-sslocsp.patch (text/x-patch), 28.69 KB, created by
Permaine Cheung
on 2011-05-04 16:06:06 UTC
(
hide
)
Description:
httpd-2.2.14-sslocsp.patch
Filename:
MIME Type:
Creator:
Permaine Cheung
Created:
2011-05-04 16:06:06 UTC
Size:
28.69 KB
patch
obsolete
>diff -uap httpd-2.2.17/modules/ssl/config.m4.sslocsp httpd-2.2.17/modules/ssl/config.m4 >--- httpd-2.2.17/modules/ssl/config.m4.sslocsp 2006-04-22 02:53:06.000000000 +0100 >+++ httpd-2.2.17/modules/ssl/config.m4 2011-04-12 10:22:31.562258721 +0100 >@@ -111,6 +111,8 @@ ssl_scache_shmcb.lo dnl > ssl_scache_dc.lo dnl > ssl_util.lo dnl > ssl_util_ssl.lo dnl >+ssl_engine_ocsp.lo dnl >+ssl_util_ocsp.lo dnl > " > dnl # hook module into the Autoconf mechanism (--enable-ssl option) > APACHE_MODULE(ssl, [SSL/TLS support (mod_ssl)], $ssl_objs, , no, [ >diff -uap httpd-2.2.17/modules/ssl/mod_ssl.c.sslocsp httpd-2.2.17/modules/ssl/mod_ssl.c >--- httpd-2.2.17/modules/ssl/mod_ssl.c.sslocsp 2010-07-12 19:47:45.000000000 +0100 >+++ httpd-2.2.17/modules/ssl/mod_ssl.c 2011-04-12 10:22:31.562258721 +0100 >@@ -211,6 +211,13 @@ static const command_rec ssl_config_cmds > "request body if a per-location SSL renegotiation is required due to " > "changed access control requirements") > >+ SSL_CMD_SRV(OCSPEnable, FLAG, >+ "Enable use of OCSP to verify certificate revocation (`on', `off')") >+ SSL_CMD_SRV(OCSPDefaultResponder, TAKE1, >+ "URL of the default OCSP Responder") >+ SSL_CMD_SRV(OCSPOverrideResponder, FLAG, >+ "Force use of the default responder URL (`on', `off')") >+ > /* Deprecated directives. */ > AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL, > "SSLLog directive is no longer supported - use ErrorLog."), >diff -uap httpd-2.2.17/modules/ssl/mod_ssl.dsp.sslocsp httpd-2.2.17/modules/ssl/mod_ssl.dsp >--- httpd-2.2.17/modules/ssl/mod_ssl.dsp.sslocsp 2007-12-29 06:09:33.000000000 +0000 >+++ httpd-2.2.17/modules/ssl/mod_ssl.dsp 2011-04-12 10:22:31.563258746 +0100 >@@ -198,6 +198,14 @@ SOURCE=.\ssl_expr_scan.c > # End Source File > # Begin Source File > >+SOURCE=.\ssl_engine_ocsp.c >+# End Source File >+# Begin Source File >+ >+SOURCE=.\ssl_util_ocsp.c >+# End Source File >+# Begin Source File >+ > SOURCE=.\ssl_scache.c > # End Source File > # Begin Source File >diff -uap httpd-2.2.17/modules/ssl/ssl_engine_config.c.sslocsp httpd-2.2.17/modules/ssl/ssl_engine_config.c >--- httpd-2.2.17/modules/ssl/ssl_engine_config.c.sslocsp 2010-07-12 19:47:45.000000000 +0100 >+++ httpd-2.2.17/modules/ssl/ssl_engine_config.c 2011-04-12 10:22:31.564257799 +0100 >@@ -126,6 +126,10 @@ static void modssl_ctx_init(modssl_ctx_t > mctx->auth.cipher_suite = NULL; > mctx->auth.verify_depth = UNSET; > mctx->auth.verify_mode = SSL_CVERIFY_UNSET; >+ >+ mctx->ocsp_enabled = FALSE; >+ mctx->ocsp_force_default = FALSE; >+ mctx->ocsp_responder = NULL; > } > > static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, >@@ -223,6 +227,10 @@ static void modssl_ctx_cfg_merge(modssl_ > cfgMergeString(auth.cipher_suite); > cfgMergeInt(auth.verify_depth); > cfgMerge(auth.verify_mode, SSL_CVERIFY_UNSET); >+ >+ cfgMergeBool(ocsp_enabled); >+ cfgMergeBool(ocsp_force_default); >+ cfgMerge(ocsp_responder, NULL); > } > > static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base, >@@ -1515,6 +1523,40 @@ const char *ssl_cmd_SSLStrictSNIVHostCh > #endif > } > >+const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, int flag) >+{ >+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); >+ >+ sc->server->ocsp_enabled = flag ? TRUE : FALSE; >+ >+#ifndef HAVE_OCSP >+ if (flag) { >+ return "OCSP support not detected in SSL library; cannot enable " >+ "OCSP validation"; >+ } >+#endif >+ >+ return NULL; >+} >+ >+const char *ssl_cmd_SSLOCSPOverrideResponder(cmd_parms *cmd, void *dcfg, int flag) >+{ >+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); >+ >+ sc->server->ocsp_force_default = flag ? TRUE : FALSE; >+ >+ return NULL; >+} >+ >+const char *ssl_cmd_SSLOCSPDefaultResponder(cmd_parms *cmd, void *dcfg, const char *arg) >+{ >+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); >+ >+ sc->server->ocsp_responder = arg; >+ >+ return NULL; >+} >+ > void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) > { > if (!ap_exists_config_define("DUMP_CERTS")) { >diff -uap httpd-2.2.17/modules/ssl/ssl_engine_kernel.c.sslocsp httpd-2.2.17/modules/ssl/ssl_engine_kernel.c >--- httpd-2.2.17/modules/ssl/ssl_engine_kernel.c.sslocsp 2010-02-27 21:00:58.000000000 +0000 >+++ httpd-2.2.17/modules/ssl/ssl_engine_kernel.c 2011-04-12 10:22:31.565257721 +0100 >@@ -1366,12 +1366,35 @@ int ssl_callback_SSLVerify(int ok, X509_ > } > > /* >- * Additionally perform CRL-based revocation checks >+ * Perform OCSP/CRL-based revocation checks > */ > if (ok) { > if (!(ok = ssl_callback_SSLVerify_CRL(ok, ctx, conn))) { > errnum = X509_STORE_CTX_get_error(ctx); > } >+ >+#ifdef HAVE_OCSP >+ /* If there was an optional verification error, it's not >+ * possible to perform OCSP validation since the issuer may be >+ * missing/untrusted. Fail in that case. */ >+ if (ok && ssl_verify_error_is_optional(errnum) >+ && sc->server->ocsp_enabled) { >+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); >+ errnum = X509_V_ERR_APPLICATION_VERIFICATION; >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn, >+ "cannot perform OCSP validation for cert " >+ "if issuer has not been verified " >+ "(optional_no_ca configured)"); >+ ok = FALSE; >+ } >+ >+ if (ok && sc->server->ocsp_enabled) { >+ ok = modssl_verify_ocsp(ctx, sc, s, conn, conn->pool); >+ if (!ok) { >+ errnum = X509_STORE_CTX_get_error(ctx); >+ } >+ } >+#endif > } > > /* >diff -uap httpd-2.2.17/modules/ssl/ssl_engine_ocsp.c.sslocsp httpd-2.2.17/modules/ssl/ssl_engine_ocsp.c >--- httpd-2.2.17/modules/ssl/ssl_engine_ocsp.c.sslocsp 2011-04-12 10:22:31.566257859 +0100 >+++ httpd-2.2.17/modules/ssl/ssl_engine_ocsp.c 2011-04-21 16:33:28.425430663 +0100 >@@ -0,0 +1,287 @@ >+/* Licensed to the Apache Software Foundation (ASF) under one or more >+ * contributor license agreements. See the NOTICE file distributed with >+ * this work for additional information regarding copyright ownership. >+ * The ASF licenses this file to You under the Apache License, Version 2.0 >+ * (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+#include "ssl_private.h" >+ >+#ifdef HAVE_OCSP >+#include "apr_base64.h" >+ >+/* Return the responder URI specified in the given certificate, or >+ * NULL if none specified. */ >+static const char *extract_responder_uri(X509 *cert, apr_pool_t *pool) >+{ >+ STACK_OF(ACCESS_DESCRIPTION) *values; >+ char *result = NULL; >+ int j; >+ >+ values = X509_get_ext_d2i(cert, NID_info_access, NULL, NULL); >+ if (!values) { >+ return NULL; >+ } >+ >+ for (j = 0; j < sk_ACCESS_DESCRIPTION_num(values) && !result; j++) { >+ ACCESS_DESCRIPTION *value = sk_ACCESS_DESCRIPTION_value(values, j); >+ >+ /* Name found in extension, and is a URI: */ >+ if (OBJ_obj2nid(value->method) == NID_ad_OCSP >+ && value->location->type == GEN_URI) { >+ result = apr_pstrdup(pool, >+ (char *)value->location->d.uniformResourceIdentifier->data); >+ } >+ } >+ >+ AUTHORITY_INFO_ACCESS_free(values); >+ >+ return result; >+} >+ >+/* Return the responder URI object which should be used in the given >+ * configuration for the given certificate, or NULL if none can be >+ * determined. */ >+static apr_uri_t *determine_responder_uri(SSLSrvConfigRec *sc, X509 *cert, >+ conn_rec *c, apr_pool_t *p) >+{ >+ apr_uri_t *u = apr_palloc(p, sizeof *u); >+ const char *s; >+ apr_status_t rv; >+ >+ /* Use default responder URL if forced by configuration, else use >+ * certificate-specified responder, falling back to default if >+ * necessary and possible. */ >+ if (sc->server->ocsp_force_default) { >+ s = sc->server->ocsp_responder; >+ } >+ else { >+ s = extract_responder_uri(cert, p); >+ >+ if (s == NULL && sc->server->ocsp_responder) { >+ s = sc->server->ocsp_responder; >+ } >+ } >+ >+ if (s == NULL) { >+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, >+ "no OCSP responder specified in certificate and " >+ "no default configured"); >+ return NULL; >+ } >+ >+ rv = apr_uri_parse(p, s, u); >+ if (rv || !u->hostname) { >+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, >+ "failed to parse OCSP responder URI '%s'", s); >+ return NULL; >+ } >+ >+ if (strcasecmp(u->scheme, "http") != 0) { >+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, >+ "cannot handle OCSP responder URI '%s'", s); >+ return NULL; >+ } >+ >+ if (!u->port) { >+ u->port = apr_uri_port_of_scheme(u->scheme); >+ } >+ >+ return u; >+} >+ >+/* 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) >+{ >+ OCSP_REQUEST *req = OCSP_REQUEST_new(); >+ X509 *issuer; >+ >+ if (X509_STORE_CTX_get1_issuer(&issuer, ctx, cert) != 1) { >+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); >+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, >+ "could not find issuer for certifiate"); >+ return NULL; >+ } >+ >+ *certid = OCSP_cert_to_id(NULL, cert, issuer); >+ X509_free(issuer); >+ if (!*certid || !OCSP_request_add0_id(req, *certid)) { >+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); >+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, >+ "could not retrieve certificate id"); >+ return NULL; >+ } >+ >+ OCSP_request_add1_nonce(req, 0, -1); >+ >+ return req; >+} >+ >+/* 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); >+ if (request) { >+ response = modssl_dispatch_ocsp_request(ruri, 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, >+ "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) { >+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, >+ "could not retrieve OCSP basic response"); >+ rc = V_OCSP_CERTSTATUS_UNKNOWN; >+ } >+ } >+ >+ if (rc == V_OCSP_CERTSTATUS_GOOD) { >+ if (OCSP_check_nonce(request, basicResponse) != 1) { >+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, >+ "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) { >+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); >+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, >+ "failed to verify the OCSP response"); >+ 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_ssl_error(APLOG_MARK, APLOG_ERR, s); >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, >+ "failed to retrieve OCSP response status"); >+ rc = V_OCSP_CERTSTATUS_UNKNOWN; >+ } >+ else { >+ rc = status; >+ } >+ >+ /* TODO: make these configurable. */ >+#define MAX_SKEW (60) >+#define MAX_AGE (360) >+ >+ /* Check whether the response is inside the defined validity >+ * period; otherwise fail. */ >+ if (rc != V_OCSP_CERTSTATUS_UNKNOWN) { >+ int vrc = OCSP_check_validity(thisup, nextup, MAX_SKEW, MAX_AGE); >+ >+ if (vrc != 1) { >+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s); >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, >+ "OCSP response outside validity period"); >+ 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"); >+ >+ ap_log_cerror(APLOG_MARK, level, 0, c, >+ "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; >+} >+ >+int modssl_verify_ocsp(X509_STORE_CTX *ctx, SSLSrvConfigRec *sc, >+ server_rec *s, conn_rec *c, apr_pool_t *pool) >+{ >+ X509 *cert = X509_STORE_CTX_get_current_cert(ctx); >+ apr_pool_t *vpool; >+ int rv; >+ >+ /* Create a temporary pool to constrain memory use (the passed-in >+ * pool may be e.g. a connection pool). */ >+ apr_pool_create(&vpool, pool); >+ >+ rv = verify_ocsp_status(cert, ctx, c, sc, s, vpool); >+ >+ apr_pool_destroy(vpool); >+ >+ /* Propagate the verification status back to the passed-in >+ * context. */ >+ switch (rv) { >+ case V_OCSP_CERTSTATUS_GOOD: >+ X509_STORE_CTX_set_error(ctx, X509_V_OK); >+ break; >+ >+ case V_OCSP_CERTSTATUS_REVOKED: >+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); >+ break; >+ >+ case V_OCSP_CERTSTATUS_UNKNOWN: >+ /* correct error code for application errors? */ >+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); >+ break; >+ } >+ >+ return rv == V_OCSP_CERTSTATUS_GOOD; >+} >+#endif /* HAVE_OCSP */ >diff -uap httpd-2.2.17/modules/ssl/ssl_private.h.sslocsp httpd-2.2.17/modules/ssl/ssl_private.h >--- httpd-2.2.17/modules/ssl/ssl_private.h.sslocsp 2010-07-12 19:47:45.000000000 +0100 >+++ httpd-2.2.17/modules/ssl/ssl_private.h 2011-04-12 10:22:31.567257776 +0100 >@@ -461,6 +461,12 @@ typedef struct { > X509_STORE *crl; > > modssl_auth_ctx_t auth; >+ >+ BOOL ocsp_enabled; /* true if OCSP verification enabled */ >+ BOOL ocsp_force_default; /* true if the default responder URL is >+ * used regardless of per-cert URL */ >+ const char *ocsp_responder; /* default responder URL */ >+ > } modssl_ctx_t; > > struct SSLSrvConfigRec { >@@ -567,6 +573,10 @@ const char *ssl_cmd_SSLProxyCheckPeerCN > > const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag); > >+const char *ssl_cmd_SSLOCSPOverrideResponder(cmd_parms *cmd, void *dcfg, int flag); >+const char *ssl_cmd_SSLOCSPDefaultResponder(cmd_parms *cmd, void *dcfg, const char *arg); >+const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, int flag); >+ > /** module initialization */ > int ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); > void ssl_init_Engine(server_rec *, apr_pool_t *); >@@ -708,6 +718,22 @@ void modssl_var_extract_dns(apr_table_t > > #define APR_SHM_MAXSIZE (64 * 1024 * 1024) > >+#ifdef HAVE_OCSP >+/* Perform OCSP validation of the current cert in the given context. >+ * Returns non-zero on success or zero on failure. On failure, the >+ * context error code is set. */ >+int modssl_verify_ocsp(X509_STORE_CTX *ctx, SSLSrvConfigRec *sc, >+ server_rec *s, conn_rec *c, apr_pool_t *pool); >+ >+/* OCSP helper interface; dispatches the given OCSP request to the >+ * responder at the given URI. Returns the decoded OCSP response >+ * object, or NULL on error (in which case, errors will have been >+ * logged). Pool 'p' is used for temporary allocations. */ >+OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri, >+ OCSP_REQUEST *request, >+ conn_rec *c, apr_pool_t *p); >+#endif >+ > #endif /* SSL_PRIVATE_H */ > /** @} */ > >diff -uap httpd-2.2.17/modules/ssl/ssl_toolkit_compat.h.sslocsp httpd-2.2.17/modules/ssl/ssl_toolkit_compat.h >--- httpd-2.2.17/modules/ssl/ssl_toolkit_compat.h.sslocsp 2010-07-12 19:47:45.000000000 +0100 >+++ httpd-2.2.17/modules/ssl/ssl_toolkit_compat.h 2011-04-12 10:22:31.568257401 +0100 >@@ -38,6 +38,13 @@ > #include <openssl/evp.h> > #include <openssl/rand.h> > #include <openssl/x509v3.h> >+ >+#if OPENSSL_VERSION_NUMBER >= 0x00907000 >+#define HAVE_OCSP >+#include <openssl/x509_vfy.h> >+#include <openssl/ocsp.h> >+#endif >+ > /** Avoid tripping over an engine build installed globally and detected > * when the user points at an explicit non-engine flavor of OpenSSL > */ >diff -uap httpd-2.2.17/modules/ssl/ssl_util_ocsp.c.sslocsp httpd-2.2.17/modules/ssl/ssl_util_ocsp.c >--- httpd-2.2.17/modules/ssl/ssl_util_ocsp.c.sslocsp 2011-04-12 10:22:31.568257401 +0100 >+++ httpd-2.2.17/modules/ssl/ssl_util_ocsp.c 2011-04-12 10:22:31.568257401 +0100 >@@ -0,0 +1,307 @@ >+/* Licensed to the Apache Software Foundation (ASF) under one or more >+ * contributor license agreements. See the NOTICE file distributed with >+ * this work for additional information regarding copyright ownership. >+ * The ASF licenses this file to You under the Apache License, Version 2.0 >+ * (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+/* This file implements an OCSP client including a toy HTTP/1.0 >+ * client. Once httpd depends on a real HTTP client library, most of >+ * this can be thrown away. */ >+ >+#include "ssl_private.h" >+ >+#ifdef HAVE_OCSP >+ >+#include "apr_buckets.h" >+#include "apr_uri.h" >+ >+/* Serialize an OCSP request which will be sent to the responder at >+ * given URI to a memory BIO object, which is returned. */ >+static BIO *serialize_request(OCSP_REQUEST *req, const apr_uri_t *uri) >+{ >+ BIO *bio; >+ int len; >+ >+ len = i2d_OCSP_REQUEST(req, NULL); >+ >+ bio = BIO_new(BIO_s_mem()); >+ >+ BIO_printf(bio, "POST %s%s%s HTTP/1.0\r\n" >+ "Host: %s:%d\r\n" >+ "Content-Type: application/ocsp-request\r\n" >+ "Content-Length: %d\r\n" >+ "\r\n", >+ uri->path ? uri->path : "/", >+ uri->query ? "?" : "", uri->query ? uri->query : "", >+ uri->hostname, uri->port, len); >+ >+ if (i2d_OCSP_REQUEST_bio(bio, req) != 1) { >+ BIO_free(bio); >+ return NULL; >+ } >+ >+ return bio; >+} >+ >+/* Send the OCSP request serialized into BIO 'request' to the >+ * responder at given server given by URI. Returns socket object or >+ * NULL on error. */ >+static apr_socket_t *send_request(BIO *request, const apr_uri_t *uri, >+ conn_rec *c, apr_pool_t *p) >+{ >+ apr_status_t rv; >+ apr_sockaddr_t *sa; >+ apr_socket_t *sd; >+ char buf[HUGE_STRING_LEN]; >+ int len; >+ >+ rv = apr_sockaddr_info_get(&sa, uri->hostname, APR_UNSPEC, uri->port, 0, p); >+ if (rv) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "could not resolve address of OCSP responder %s", >+ uri->hostinfo); >+ return NULL; >+ } >+ >+ /* establish a connection to the OCSP responder */ >+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, >+ "connecting to OCSP responder '%s'", uri->hostinfo); >+ >+ /* Cycle through address until a connect() succeeds. */ >+ for (; sa; sa = sa->next) { >+ rv = apr_socket_create(&sd, sa->family, SOCK_STREAM, APR_PROTO_TCP, p); >+ if (rv == APR_SUCCESS) { >+ /* Inherit the default I/O timeout. */ >+ apr_socket_timeout_set(sd, c->base_server->timeout); >+ >+ rv = apr_socket_connect(sd, sa); >+ if (rv == APR_SUCCESS) { >+ break; >+ } >+ apr_socket_close(sd); >+ } >+ } >+ >+ if (sa == NULL) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "could not connect to OCSP responder '%s'", >+ uri->hostinfo); >+ apr_socket_close(sd); >+ return NULL; >+ } >+ >+ /* send the request and get a response */ >+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, >+ "sending request to OCSP responder"); >+ >+ while ((len = BIO_read(request, buf, sizeof buf)) > 0) { >+ char *wbuf = buf; >+ apr_size_t remain = len; >+ >+ do { >+ apr_size_t wlen = remain; >+ >+ rv = apr_socket_send(sd, wbuf, &wlen); >+ wbuf += remain; >+ remain -= wlen; >+ } while (rv == APR_SUCCESS && remain > 0); >+ >+ if (rv) { >+ apr_socket_close(sd); >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "failed to send request to OCSP responder '%s'", >+ uri->hostinfo); >+ return NULL; >+ } >+ } >+ >+ return sd; >+} >+ >+/* Return a pool-allocated NUL-terminated line, with CRLF stripped, >+ * read from brigade 'bbin' using 'bbout' as temporary storage. */ >+static char *get_line(apr_bucket_brigade *bbout, apr_bucket_brigade *bbin, >+ conn_rec *c, apr_pool_t *p) >+{ >+ apr_status_t rv; >+ apr_size_t len; >+ char *line; >+ >+ apr_brigade_cleanup(bbout); >+ >+ rv = apr_brigade_split_line(bbout, bbin, APR_BLOCK_READ, 8192); >+ if (rv) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "failed reading line from OCSP server"); >+ return NULL; >+ } >+ >+ rv = apr_brigade_pflatten(bbout, &line, &len, p); >+ if (rv) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "failed reading line from OCSP server"); >+ return NULL; >+ } >+ >+ if (len && line[len-1] != APR_ASCII_LF) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "response header line too long from OCSP server"); >+ return NULL; >+ } >+ >+ line[len-1] = '\0'; >+ if (len > 1 && line[len-2] == APR_ASCII_CR) { >+ line[len-2] = '\0'; >+ } >+ >+ return line; >+} >+ >+/* Maximum values to prevent eating RAM forever. */ >+#define MAX_HEADERS (256) >+#define MAX_CONTENT (2048 * 1024) >+ >+/* 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, >+ "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, >+ "OCSP response header: %s", line); >+ } >+ >+ if (count == MAX_HEADERS) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, >+ "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, >+ "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 || (rv == APR_SUCCESS && len == 0)) { >+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, >+ "OCSP response: got EOF"); >+ break; >+ } >+ if (rv != APR_SUCCESS) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "error reading response from OCSP server"); >+ return NULL; >+ } >+ count += len; >+ if (count > MAX_CONTENT) { >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, >+ "OCSP response size exceeds %u byte limit", >+ MAX_CONTENT); >+ return NULL; >+ } >+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, >+ "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) { >+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server); >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, >+ "failed to decode OCSP response data"); >+ } >+ >+ return response; >+} >+ >+OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri, >+ 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) { >+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server); >+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, >+ "could not serialize OCSP request"); >+ return NULL; >+ } >+ >+ sd = send_request(bio, uri, 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; >+} >+ >+#endif /* HAVE_OCSP */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 899392
: 681363