DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG· RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://issues.apache.org/bugzilla/show_bug.cgi?id=41123>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND· INSERTED IN THE BUG DATABASE.
http://issues.apache.org/bugzilla/show_bug.cgi?id=41123 [EMAIL PROTECTED] changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #20958|Small corrections in error |Small corrections in error description|handling and OCSP response |handling, OCSP response |logging |logging, and memory leaks | |corrections (remarks from | |OpenSSL developers) ------- Additional Comments From [EMAIL PROTECTED] 2007-10-12 06:22 ------- (From update of attachment 20958) diff -uaEbwNp orig/ssl_ocsp.c ./ssl_ocsp.c --- orig/ssl_ocsp.c 1970-01-01 01:00:00.000000000 +0100 +++ ./ssl_ocsp.c 2007-10-11 16:37:20.866178500 +0200 @@ -0,0 +1,441 @@ +/* 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. + */ + +/* _ _ + * _ __ ___ ___ __| | ___ ___| | mod_ssl + * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL + * | | | | | | (_) | (_| | \__ \__ \ | + * |_| |_| |_|\___/ \__,_|___|___/___/_| + * |_____| + * ssl_ocsp.c + * The SSL OCSP checking + * + * Developed by Marc Stern, for Approach Belgium / CSC / Belgian Government + * based on code developed by Zetes Pass + * + * This code was added to support the Belgian Electronic Identity Card + * + * The OCSP responder URL is read from the certificate itself + * + */ + /* ``When the only tool you own is a hammer, + every problem begins to resemble a nail.´´ + */ + +#include "mod_ssl.h" +#include "ssl_private.h" +#include "apr_base64.h" + +#define X509_NAME2STR(name_) X509_NAME_oneline(name_, NULL, 0) +#define X509_SUBJ_NAME(cert_) X509_NAME2STR(X509_get_subject_name(cert_)) +#define X509_ISSUER_NAME(cert_) X509_NAME2STR(X509_get_issuer_name(cert_)) + + +static char *ap_ocsp_ASN1_Int2Str(ASN1_INTEGER *data, apr_pool_t *pool) +{ + char *result = (char *)apr_palloc(pool, 100); /* 100 should be enough */ + char *buf = NULL; + BIGNUM *bn = ASN1_INTEGER_to_BN(data, NULL); + + *result = 0; + if (bn && !BN_is_zero(bn)) { + buf = BN_bn2hex(bn); + if (buf) { + strncpy(result, buf, sizeof(result) - 1); + result[sizeof(result) - 1 ] = 0; + } + } + + if (bn) BN_free(bn); + if (buf) OPENSSL_free(buf); + return result; +} + +static char *ap_ocsp_get_ocsp_uri(X509 *cert, apr_pool_t *pool) +{ + int crit, j; + STACK_OF(ACCESS_DESCRIPTION) *values = + (STACK_OF(ACCESS_DESCRIPTION) *) + X509_get_ext_d2i(cert, NID_info_access, &crit, NULL); + if (! values) return NULL; + + for (j = 0; j < sk_ACCESS_DESCRIPTION_num(values); j++) { + ACCESS_DESCRIPTION *value = sk_ACCESS_DESCRIPTION_value(values, j); + if(OBJ_obj2nid(value->method) == NID_ad_OCSP) { + /* Name found in extension */ + char *result; + + /* Check that it is a URI */ + if (value->location->type != GEN_URI) + continue; + + result = apr_pstrdup(pool, + (char *)value->location->d.uniformResourceIdentifier->data); + AUTHORITY_INFO_ACCESS_free(values); + return result; + } + } + + sk_ACCESS_DESCRIPTION_free(values); + //AUTHORITY_INFO_ACCESS_free(values); + return NULL; +} + + +static BIO *ap_ocsp_connect(const char *host, int port) +{ + BIO *connection = BIO_new_connect((char *)host); + if (!connection) return 0; + + BIO_set_conn_int_port(connection, &port); + if (BIO_do_connect(connection) <= 0) { + /* Not needed - default: BIO_set_close(connection, BIO_CLOSE); */ + BIO_free_all(connection); + return NULL; + } + + return connection; + +} + + +static OCSP_RESPONSE *ap_ocsp_sendreq(const char *ocspHost, const char *ocspPort, const char *ocspPath, OCSP_REQUEST *request, server_rec *s) +{ + BIO *bio = NULL; + OCSP_RESPONSE *response = NULL; + + /* establish a connection to the OCSP responder */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Connect to OCSP responder '%s:%s'", ocspHost, ocspPort); + bio = ap_ocsp_connect(ocspHost, atoi(ocspPort)); + if (!bio) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot connect to OCSP responder '%s:%s'", ocspHost, ocspPort); + return NULL; + } + + /* send the request and get a response */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "sending request to OCSP responder"); + response = OCSP_sendreq_bio(bio, (char *)ocspPath, request); + if (!response) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot send request to OCSP responder '%s'", ocspHost); + } + + BIO_free_all(bio); + + return response; +} + + +static int ap_ocsp_verify_ocsp(X509 *cert, X509_STORE_CTX *ctx, server_rec *s, + int *ocspStatus, apr_pool_t *pool) +{ + int rc = SSL_OCSP_OK; + X509 *issuer = NULL; + char *ocspUrl = NULL, *ocspHost = NULL, *ocspPort = NULL, *ocspPath = NULL; + BIO * bio = NULL; + OCSP_RESPONSE * response = NULL; + OCSP_BASICRESP * basicResponse = NULL; + OCSP_REQUEST * request = NULL; + OCSP_CERTID * certID = NULL; + int ssl = 0; + SSLSrvConfigRec *sc = mySrvConfig(s); + char *subj_name = X509_SUBJ_NAME(cert); + char *issuer_name = X509_ISSUER_NAME(cert); + + *ocspStatus = V_OCSP_CERTSTATUS_UNKNOWN; + X509_STORE_CTX_set_error(ctx, X509_V_ERR_APPLICATION_VERIFICATION); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "OCSP check - cert='%s', issuer='%s'", subj_name, issuer_name); + + + /* First look if we force the responder url*/ + if (sc->server->OCSPForceResponderURL) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Force the url of responder to: %s", sc->server->OCSPForceResponderURL); + ocspUrl = sc->server->OCSPForceResponderURL; + } + /* if not, look inside the certificate if we have one */ + else { + /* Get OCSP Responder URI (only first one) */ + ocspUrl = ap_ocsp_get_ocsp_uri(cert, pool); + if (ocspUrl) + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "OCSP responder from certificate: %s", ocspUrl); + } + + if (!ocspUrl && sc->server->OCSPDefaultResponderURL) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "No Responder URL in certificate - using default: %s", + sc->server->OCSPDefaultResponderURL); + ocspUrl = sc->server->OCSPDefaultResponderURL; + } + + if (!ocspUrl) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Cannot get OCSP responder URL from '%s' and no default URL Responder", + subj_name); + rc = SSL_OCSP_ERROR_PARSE_URL; + } + + if (rc == SSL_OCSP_OK) { + if (!OCSP_parse_url(ocspUrl, &ocspHost, &ocspPort, &ocspPath, &ssl)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot parse OCSP responder URL from '%s'", + subj_name); + rc = SSL_OCSP_ERROR_PARSE_URL; + } + } + + + if (rc == SSL_OCSP_OK) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Create new OCSP request"); + request = OCSP_REQUEST_new(); + if (!request) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot create new OCSP request"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if (rc == SSL_OCSP_OK) { + /* Get issuer */ + int r; + /* Enhancement: ctx->chain is already ordered -> extract 2nd ? */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Get Issuer"); + r = X509_STORE_CTX_get1_issuer(&issuer, ctx, cert); + if (r != 1) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot get issuer of '%s'. rc=%d", subj_name, rc); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if (rc == SSL_OCSP_OK) { + certID = OCSP_cert_to_id(0, cert, issuer); + if (!certID || !OCSP_request_add0_id(request, certID)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s + , "Cannot get certificate id from '%s'", subj_name); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if (rc == SSL_OCSP_OK) { + OCSP_request_add1_nonce(request, 0, -1); + + /* To use a proxy, do the following + - ocspHost = proxyHost; + - ocspPort = proxyPort; + - ocspPath = ocspUrl; + */ + + /* establish a connection to the OCSP responder */ + response = ap_ocsp_sendreq(ocspHost, ocspPort, ocspPath, request, s); + if (!response) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot send request to OCSP responder '%s'", ocspHost); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + + if ( (rc == SSL_OCSP_OK) && (s->loglevel >= APLOG_DEBUG) ) { + /* Log OCSP answer (complete OpenSSL buffer) */ + char *buf = apr_palloc(pool, + apr_base64_encode_len(response->responseBytes->response->length) + 1); + if (buf) { + apr_base64_encode(buf, + (const char*)response->responseBytes->response->data, + response->responseBytes->response->length); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "OCSP response (OpenSSL bufer): serial=%s | dn=%s | %s", + ap_ocsp_ASN1_Int2Str(X509_get_serialNumber(cert), pool), + X509_SUBJ_NAME(cert), buf); + } + else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Cannot allocate buffer"); + } + } + + if (rc == SSL_OCSP_OK) { + int r; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "Analyse OCSP request answer"); + r = OCSP_response_status(response); + if (r != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Bad OCSP responder answer. rc=%d", rc); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if ( (rc == SSL_OCSP_OK) && (s->loglevel >= APLOG_DEBUG) ) { + /* Log OCSP answer (only the "bare" response) */ + int len = i2d_OCSP_RESPONSE(response, NULL); + if (len <= 0) + rc = SSL_OCSP_ERROR_INTERNAL; + else { + unsigned char *buf1, *buf2; + buf1 = buf2 = (unsigned char *)apr_palloc(pool, len); + if (!buf1) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Out of memory"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + else { + if (i2d_OCSP_RESPONSE(response, &buf1) != len) + rc = SSL_OCSP_ERROR_INTERNAL; + else { + /* contents is in buf2, because buf1 is now pointing + to the end of the structure */ + char h[] = "OCSP response : "; + int len64 = apr_base64_encode_len(len); + char *msg = (char *)apr_palloc(pool, len64 + strlen(h) + 1); + if (msg) { + strcpy(msg, h); + apr_base64_encode(msg + strlen(h), buf2, len); + msg[strlen(h) + len64 + 1] = 0; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, msg); + } + } + } + } + } + + if (rc == SSL_OCSP_OK) { + basicResponse = OCSP_response_get1_basic(response); + if (!basicResponse) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Bad OCSP responder answer"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if (rc == SSL_OCSP_OK) { + if (OCSP_check_nonce(request, basicResponse) <= 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Bad OCSP responder answer (bad nonce)"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if (rc == SSL_OCSP_OK) { + if (OCSP_basic_verify(basicResponse, 0, ctx->ctx, + sc->server->OCSPResponderVerifyFlag) <= 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Error verifying OCSP responder answer"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if (rc == SSL_OCSP_OK) { + int ocspReason = -1; + ASN1_GENERALIZEDTIME * ocspProducedAt, *ocspThisUpdate, + *ocspNextUpdate; + rc = OCSP_resp_find_status(basicResponse, certID, ocspStatus, + &ocspReason, &ocspProducedAt, + &ocspThisUpdate, &ocspNextUpdate); + if (rc == 0) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Bad OCSP status"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "OCSP validation completed: status=%d", *ocspStatus); + rc = SSL_OCSP_OK; + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Cleanup OCSP code"); + if (issuer) X509_free(issuer); + if (subj_name) OPENSSL_free(subj_name); + if (issuer_name) OPENSSL_free(issuer_name); + if (request) OCSP_REQUEST_free(request); + if (response) OCSP_RESPONSE_free(response); + if (basicResponse) OCSP_BASICRESP_free(basicResponse); + if (ocspHost) OPENSSL_free(ocspHost); + if (ocspPort) OPENSSL_free(ocspPort); + if (ocspPath) OPENSSL_free(ocspPath); + /* certID is just a pointer, nothing to free */ + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Ending cleanup OCSP code"); + return rc; +} + +int ssl_cmd_VerifyOCSP(X509_STORE_CTX *ctx, server_rec *s, int *ocspStatus, + apr_pool_t *pool) +{ + int rc = SSL_OCSP_OK, i; + X509 *cert = X509_STORE_CTX_get_current_cert(ctx); + X509_STORE_CTX *ocspCtx = NULL; + X509_STORE *store = NULL; + SSLSrvConfigRec *sc = mySrvConfig(s); + char *subj_name = X509_SUBJ_NAME(cert); + char *issuer_name = X509_ISSUER_NAME(cert); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Validating certificate '%s', issuer: '%s'", + subj_name, issuer_name); + + /* Store certif chain in a store */ + if (!ctx->chain) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "No certificate chain"); + return SSL_OCSP_ERROR_INTERNAL; + } + + /* + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "certificates chain length: %d", ctx->chain->num); + */ + + store = X509_STORE_new(); + if (!store) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot create a new X509 store"); + return SSL_OCSP_ERROR_INTERNAL; + } + + for (i = 0; i < ctx->chain->num; i++) + if (!X509_STORE_add_cert(store, sk_X509_value(ctx->chain, i))) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot add certificate to X509 store"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + + if (rc == SSL_OCSP_OK) { + ocspCtx = X509_STORE_CTX_new(); + if (!ocspCtx) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot create a new X509 context"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + if (rc == SSL_OCSP_OK) { + if (X509_STORE_CTX_init(ocspCtx, store, cert, 0) != 1) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "Cannot initialise the new X509 context"); + rc = SSL_OCSP_ERROR_INTERNAL; + } + } + + if (rc == SSL_OCSP_OK) + rc = ap_ocsp_verify_ocsp(cert, ocspCtx, s, ocspStatus, pool); + + if (subj_name) OPENSSL_free(subj_name); + if (issuer_name) OPENSSL_free(issuer_name); + if (store) X509_STORE_free(store); + if (ocspCtx) X509_STORE_CTX_free(ocspCtx); + return rc; +} -- Configure bugmail: http://issues.apache.org/bugzilla/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug, or are watching the assignee. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
