Return-Path: X-Original-To: apmail-tomcat-dev-archive@www.apache.org Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C3E2990B6 for ; Fri, 24 Feb 2012 07:44:16 +0000 (UTC) Received: (qmail 76514 invoked by uid 500); 24 Feb 2012 07:44:15 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 76428 invoked by uid 500); 24 Feb 2012 07:44:15 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 76328 invoked by uid 99); 24 Feb 2012 07:44:11 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 24 Feb 2012 07:44:11 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED,T_FRT_SLUT X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 24 Feb 2012 07:44:06 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 538502388865 for ; Fri, 24 Feb 2012 07:43:45 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1293119 - in /tomcat/native/branches/1.1.x: native/configure.in native/include/ssl_private.h native/src/sslutils.c xdocs/miscellaneous/changelog.xml Date: Fri, 24 Feb 2012 07:43:45 -0000 To: dev@tomcat.apache.org From: mturk@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120224074345.538502388865@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: mturk Date: Fri Feb 24 07:43:44 2012 New Revision: 1293119 URL: http://svn.apache.org/viewvc?rev=1293119&view=rev Log: BZ45392 Apply modified patch. OCSP is enabled is explicitly configure with --enable-ocsp at build time Modified: tomcat/native/branches/1.1.x/native/configure.in tomcat/native/branches/1.1.x/native/include/ssl_private.h tomcat/native/branches/1.1.x/native/src/sslutils.c tomcat/native/branches/1.1.x/xdocs/miscellaneous/changelog.xml Modified: tomcat/native/branches/1.1.x/native/configure.in URL: http://svn.apache.org/viewvc/tomcat/native/branches/1.1.x/native/configure.in?rev=1293119&r1=1293118&r2=1293119&view=diff ============================================================================== --- tomcat/native/branches/1.1.x/native/configure.in (original) +++ tomcat/native/branches/1.1.x/native/configure.in Fri Feb 24 07:43:44 2012 @@ -151,6 +151,17 @@ AC_ARG_ENABLE(openssl, esac ]) +AC_ARG_ENABLE(ocsp, +[AS_HELP_STRING([--enable-openssl],[Turn on OpenSSL OCSP verification support])], +[ + case "${enableval}" in + yes ) + APR_ADDTO(CFLAGS, [-DHAVE_OPENSSL_OCSP]) + AC_MSG_RESULT([Enabling OCSP verification support...]) + ;; + esac +]) + if $use_openssl ; then TCN_CHECK_SSL_TOOLKIT fi Modified: tomcat/native/branches/1.1.x/native/include/ssl_private.h URL: http://svn.apache.org/viewvc/tomcat/native/branches/1.1.x/native/include/ssl_private.h?rev=1293119&r1=1293118&r2=1293119&view=diff ============================================================================== --- tomcat/native/branches/1.1.x/native/include/ssl_private.h (original) +++ tomcat/native/branches/1.1.x/native/include/ssl_private.h Fri Feb 24 07:43:44 2012 @@ -204,6 +204,11 @@ "In order to read them you have to provide the pass phrases.\n" \ "Enter password :" +#define OCSP_STATUS_OK 0 +#define OCSP_STATUS_REVOKED 1 +#define OCSP_STATUS_UNKNOWN 2 + + extern void *SSL_temp_keys[SSL_TMP_KEY_MAX]; typedef struct { @@ -308,4 +313,7 @@ void SSL_vhost_algo_id(const unsi int SSL_CTX_use_certificate_chain(SSL_CTX *, const char *, int); int SSL_callback_SSL_verify(int, X509_STORE_CTX *); int SSL_rand_seed(const char *file); +int SSL_ocsp_request(X509 *cert, X509 *issuer); + + #endif /* SSL_PRIVATE_H */ Modified: tomcat/native/branches/1.1.x/native/src/sslutils.c URL: http://svn.apache.org/viewvc/tomcat/native/branches/1.1.x/native/src/sslutils.c?rev=1293119&r1=1293118&r2=1293119&view=diff ============================================================================== --- tomcat/native/branches/1.1.x/native/src/sslutils.c (original) +++ tomcat/native/branches/1.1.x/native/src/sslutils.c Fri Feb 24 07:43:44 2012 @@ -21,16 +21,31 @@ */ #include "tcn.h" -#include "apr_thread_mutex.h" -#include "apr_poll.h" #ifdef HAVE_OPENSSL +#include "apr_poll.h" #include "ssl_private.h" #ifdef WIN32 extern int WIN32_SSL_password_prompt(tcn_pass_cb_t *data); #endif +#if defined(HAVE_SSL_OCSP) && defined(HAVE_OPENSSL_OCSP) +#define HAS_OCSP_ENABLED 1 +#else +#define HAS_OCSP_ENABLED 0 +#endif +#if HAS_OCSP_ENABLED +#include +#include +/* defines with the values as seen by the asn1parse -dump openssl command */ +#define ASN1_SEQUENCE 0x30 +#define ASN1_OID 0x06 +#define ASN1_STRING 0x86 + +static int ssl_verify_OCSP(int ok, X509_STORE_CTX *ctx); +#endif + /* _________________________________________________________________ ** ** Additional High-Level Functions for OpenSSL @@ -621,6 +636,8 @@ static int ssl_verify_CRL(int ok, X509_S * This OpenSSL callback function is called when OpenSSL * does client authentication and verifies the certificate chain. */ + + int SSL_callback_SSL_verify(int ok, X509_STORE_CTX *ctx) { /* Get Apache context back through OpenSSL context */ @@ -632,6 +649,7 @@ int SSL_callback_SSL_verify(int ok, X509 int errdepth = X509_STORE_CTX_get_error_depth(ctx); int verify = con->ctx->verify_mode; int depth = con->ctx->verify_depth; + int skip_crl = 0; if (verify == SSL_CVERIFY_UNSET || verify == SSL_CVERIFY_NONE) @@ -642,10 +660,28 @@ int SSL_callback_SSL_verify(int ok, X509 ok = 1; SSL_set_verify_result(ssl, X509_V_OK); } + +#if HAS_OCSP_ENABLED + /* First perform OCSP validation if possible */ + if(ok) { + int ocsp_response = ssl_verify_OCSP(ok, ctx); + if (ocsp_response == OCSP_STATUS_OK ) { + skip_crl = 1; /* we know it is valid we skip crl evaluation */ + } + else if(ocsp_response == OCSP_STATUS_REVOKED ) { + ok = 0 ; + errnum = X509_STORE_CTX_get_error(ctx); + } + else if (ocsp_response == OCSP_STATUS_UNKNOWN) { + /* TODO: do nothing for time being, continue with CRL */ + ; + } + } +#endif /* * Additionally perform CRL-based revocation checks */ - if (ok && con->ctx->crl) { + if (ok && con->ctx->crl && !skip_crl) { if (!(ok = ssl_verify_CRL(ok, ctx, con))) { errnum = X509_STORE_CTX_get_error(ctx); /* TODO: Log something */ @@ -693,8 +729,8 @@ void SSL_callback_handshake(const SSL *s * read. */ if ((where & SSL_CB_ACCEPT_LOOP) && con->reneg_state == RENEG_REJECT) { int state = SSL_get_state(ssl); - - if (state == SSL3_ST_SR_CLNT_HELLO_A + + if (state == SSL3_ST_SR_CLNT_HELLO_A || state == SSL23_ST_SR_CLNT_HELLO_A) { con->reneg_state = RENEG_ABORT; /* XXX: rejecting client initiated renegotiation @@ -708,5 +744,511 @@ void SSL_callback_handshake(const SSL *s } } - -#endif + +#if HAS_OCSP_ENABLED + +/* Function that is used to do the OCSP verification */ +static int ssl_verify_OCSP(int ok, X509_STORE_CTX *ctx) +{ + X509 *cert, *issuer; + int r = OCSP_STATUS_UNKNOWN; + + cert = X509_STORE_CTX_get_current_cert(ctx); + /* if we can't get the issuer, we cannot perform OCSP verification */ + if (X509_STORE_CTX_get1_issuer(&issuer, ctx, cert) == 1 ) { + r = SSL_ocsp_request(cert, issuer); + if (r == OCSP_STATUS_REVOKED) { + /* we set the error if we know that it is revoked */ + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); + } + else { + /* else we return unknown, so that we can continue with the crl */ + r = OCSP_STATUS_UNKNOWN; + } + X509_free(issuer); /* It appears that we should free issuer since + * X509_STORE_CTX_get1_issuer() calls X509_OBJECT_up_ref_count() + * on the issuer object (unline X509_STORE_CTX_get_current_cert() + * that just returns the pointer + */ + } + return r; +} + + +/* Helps with error handling or realloc */ +static void *apr_xrealloc(void *buf, size_t oldlen, size_t len, apr_pool_t *p) +{ + void *newp = apr_palloc(p, len); + + if(newp) + memcpy(newp, buf, oldlen); + return newp; +} + +/* parses the ocsp url and updates the ocsp_urls and nocsp_urls variables + returns 0 on success, 1 on failure */ +static int parse_ocsp_url(unsigned char *asn1, char ***ocsp_urls, + int *nocsp_urls, apr_pool_t *p) +{ + char **new_ocsp_urls, *ocsp_url; + int len, err = 0, new_nocsp_urls; + + if (*asn1 == ASN1_STRING) { + len = *++asn1; + asn1++; + new_nocsp_urls = *nocsp_urls+1; + if ((new_ocsp_urls = apr_xrealloc(*ocsp_urls,*nocsp_urls, new_nocsp_urls, p)) == NULL) + err = 1; + if (!err) { + *ocsp_urls = new_ocsp_urls; + *nocsp_urls = new_nocsp_urls; + *(*ocsp_urls + *nocsp_urls) = NULL; + if ((ocsp_url = apr_palloc(p, len + 1)) == NULL) { + err = 1; + } + else { + memcpy(ocsp_url, asn1, len); + ocsp_url[len] = '\0'; + *(*ocsp_urls + *nocsp_urls - 1) = ocsp_url; + } + } + } + return err; + +} + +/* parses the ANS1 OID and if it is an OCSP OID then calls the parse_ocsp_url function */ +static int parse_ASN1_OID(unsigned char *asn1, char ***ocsp_urls, int *nocsp_urls, apr_pool_t *p) +{ + int len, err = 0 ; + const unsigned char OCSP_OID[] = {0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01}; + + len = *++asn1; + asn1++; + if (memcmp(asn1, OCSP_OID, len) == 0) { + asn1+=len; + err = parse_ocsp_url(asn1, ocsp_urls, nocsp_urls, p); + } + return err; +} + + +/* Parses an ASN1 Sequence. It is a recursive function, since if it finds a sequence + within the sequence it calls recursively itself. This function stops when it finds + the end of the ASN1 sequence (marked by '\0'), so if there are other sequences within + the same sequence the while loop parses the sequences */ + +/* This algo was developped with AIA in mind so it was tested only with this extension */ +static int parse_ASN1_Sequence(unsigned char *asn1, char ***ocsp_urls, + int *nocsp_urls, apr_pool_t *p) +{ + int len = 0 , err = 0; + + while (!err && *asn1 != '\0') { + switch(*asn1) { + case ASN1_SEQUENCE: + len = *++asn1; + asn1++; + err = parse_ASN1_Sequence(asn1, ocsp_urls, nocsp_urls, p); + break; + case ASN1_OID: + err = parse_ASN1_OID(asn1,ocsp_urls,nocsp_urls, p); + return 0; + break; + default: + err = 1; /* we shouldn't have any errors */ + break; + } + asn1+=len; + } + return err; +} + +/* the main function that gets the ASN1 encoding string and returns + a pointer to a NULL terminated "array" of char *, that contains + the ocsp_urls */ +static char **decode_OCSP_url(ASN1_OCTET_STRING *os, apr_pool_t *p) +{ + char **response = NULL; + unsigned char *ocsp_urls; + int i, len, numofresponses = 0 ; + + len = ASN1_STRING_length(os); + + ocsp_urls = apr_palloc(p, len + 1); + memcpy(ocsp_urls,os->data, len); + ocsp_urls[len] = '\0'; + + if ((response = apr_pcalloc(p, sizeof(char *))) == NULL) + return NULL; + if (parse_ASN1_Sequence(ocsp_urls, &response, &numofresponses, p)) + response = NULL; + return response; +} + + +/* stolen from openssl ocsp command */ +static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer, + STACK_OF(OCSP_CERTID) *ids) +{ + OCSP_CERTID *id; + + if (!issuer) + return 0; + if (!*req) + *req = OCSP_REQUEST_new(); + if (!*req) + return 0; + id = OCSP_cert_to_id(NULL, cert, issuer); + if (!id || !sk_OCSP_CERTID_push(ids, id)) + return 0; + return OCSP_request_add0_id(*req, id); +} + + +/* Creates the APR socket and connect to the hostname. Returns the + socket or NULL if there is an error. +*/ +static apr_socket_t *make_socket(char *hostname, int port, apr_pool_t *mp) +{ + int r = 0; + apr_sockaddr_t *sa_in; + apr_status_t status; + apr_socket_t *sock = NULL; + + + status = apr_sockaddr_info_get(&sa_in, hostname, APR_INET, port, 0, mp); + + if (status == APR_SUCCESS) + status = apr_socket_create(&sock, sa_in->family, SOCK_STREAM, APR_PROTO_TCP, mp); + if (status == APR_SUCCESS) + status = apr_socket_connect(sock, sa_in); + + if (status == APR_SUCCESS) + return sock; + return NULL; +} + + +/* Creates the request in a memory BIO in order to send it to the OCSP server. + Most parts of this function are taken from mod_ssl support for OCSP (with some + minor modifications +*/ +static BIO *serialize_request(OCSP_REQUEST *req, char *host, int port, char *path) +{ + BIO *bio; + int len; + + len = i2d_OCSP_REQUEST(req, NULL); + + bio = BIO_new(BIO_s_mem()); + + BIO_printf(bio, "POST %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", + path, host, port, len); + + if (i2d_OCSP_REQUEST_bio(bio, req) != 1) { + BIO_free(bio); + return NULL; + } + + return bio; +} + + +/* Send the OCSP request to the OCSP server. Taken from mod_ssl OCSP support */ +static int ocsp_send_req(apr_socket_t *sock, BIO *req) +{ + int len; + char buf[TCN_BUFFER_SZ]; + apr_status_t rv; + int ok = 1; + + while ((len = BIO_read(req, buf, sizeof buf)) > 0) { + char *wbuf = buf; + apr_size_t remain = len; + + do { + apr_size_t wlen = remain; + rv = apr_socket_send(sock, wbuf, &wlen); + wbuf += remain; + remain -= wlen; + } while (rv == APR_SUCCESS && remain > 0); + + if (rv != APR_SUCCESS) { + apr_socket_close(sock); + ok = 0; + } + } + + return ok; +} + + + +/* Parses the buffer from the response and extracts the OCSP response. + Taken from openssl library */ +static OCSP_RESPONSE *parse_ocsp_resp(char *buf, int len) +{ + BIO *mem = NULL; + char tmpbuf[1024]; + OCSP_RESPONSE *resp = NULL; + char *p, *q, *r; + int retcode; + + mem = BIO_new(BIO_s_mem()); + if(mem == NULL) + return NULL; + + BIO_write(mem, buf, len); /* write the buffer to the bio */ + if (BIO_gets(mem, tmpbuf, 512) <= 0) { + OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR); + goto err; + } + /* Parse the HTTP response. This will look like this: + * "HTTP/1.0 200 OK". We need to obtain the numeric code and + * (optional) informational message. + */ + + /* Skip to first white space (passed protocol info) */ + for (p = tmpbuf; *p && !apr_isspace(*p); p++) + continue; + if (!*p) { + goto err; + } + /* Skip past white space to start of response code */ + while (apr_isspace(*p)) + p++; + if (!*p) { + goto err; + } + /* Find end of response code: first whitespace after start of code */ + for (q = p; *q && !apr_isspace(*q); q++) + continue; + if (!*q) { + goto err; + } + /* Set end of response code and start of message */ + *q++ = 0; + /* Attempt to parse numeric code */ + retcode = strtoul(p, &r, 10); + if (*r) + goto err; + /* Skip over any leading white space in message */ + while (apr_isspace(*q)) + q++; + if (*q) { + /* Finally zap any trailing white space in message (include CRLF) */ + /* We know q has a non white space character so this is OK */ + for(r = q + strlen(q) - 1; apr_isspace(*r); r--) *r = 0; + } + if (retcode != 200) { + goto err; + } + /* Find blank line marking beginning of content */ + while (BIO_gets(mem, tmpbuf, 512) > 0) { + for (p = tmpbuf; apr_isspace(*p); p++) + continue; + if (!*p) + break; + } + if (*p) { + goto err; + } + if (!(resp = d2i_OCSP_RESPONSE_bio(mem, NULL))) { + goto err; + } +err: + BIO_free(mem); + return resp; +} + + +/* Reads the respnse from the APR socket to a buffer, and parses the buffer to + return the OCSP response */ +#define ADDLEN 512 +static OCSP_RESPONSE *ocsp_get_resp(apr_socket_t *sock) +{ + int buflen = 0, totalread = 0; + apr_size_t readlen; + char *buf, tmpbuf[ADDLEN]; + apr_status_t rv = APR_SUCCESS; + apr_pool_t *p; + OCSP_RESPONSE *resp; + + apr_pool_create(&p, NULL); + buflen = ADDLEN; + buf = apr_palloc(p, buflen); + if (buf == NULL) { + apr_pool_destroy(p); + return NULL; + } + + while (rv == APR_SUCCESS ) { + readlen = sizeof(tmpbuf); + rv = apr_socket_recv(sock, tmpbuf, &readlen); + if (rv == APR_SUCCESS) { /* if we have read something .. we can put it in the buffer*/ + if ((totalread + readlen) >= buflen) { + buf = apr_xrealloc(buf, buflen, buflen + ADDLEN, p); + if (buf == NULL) { + apr_pool_destroy(p); + return NULL; + } + buflen += ADDLEN; /* if needed we enlarge the buffer */ + } + memcpy(buf + totalread, tmpbuf, readlen); /* the copy to the buffer */ + totalread += readlen; /* update the total bytes read */ + } + else { + if (rv == APR_EOF && readlen == 0) + ; /* EOF, normal situation */ + else if (readlen == 0) { + /* Not success, and readlen == 0 .. some error */ + apr_pool_destroy(p); + return NULL; + } + } + } + + resp = parse_ocsp_resp(buf, buflen); + apr_pool_destroy(p); + return resp; +} + +/* Creates and OCSP request and returns the OCSP_RESPONSE */ +static OCSP_RESPONSE *get_ocsp_response(X509 *cert, X509 *issuer, char *url) +{ + OCSP_RESPONSE *ocsp_resp = NULL; + OCSP_REQUEST *ocsp_req = NULL; + BIO *bio_req; + char *hostname, *path, *c_port; + int port, use_ssl; + STACK_OF(OCSP_CERTID) *ids = NULL; + int ok = 0; + apr_socket_t *apr_sock = NULL; + apr_pool_t *mp; + + apr_pool_create(&mp, NULL); + ids = sk_OCSP_CERTID_new_null(); + + /* problem parsing the URL */ + if (OCSP_parse_url(url,&hostname, &c_port, &path, &use_ssl) == 0 ) { + sk_OCSP_CERTID_free(ids); + return NULL; + } + + /* Create the OCSP request */ + if (sscanf(c_port, "%d", &port) != 1) + goto end; + ocsp_req = OCSP_REQUEST_new(); + if (ocsp_req == NULL) + return NULL; + if (add_ocsp_cert(&ocsp_req,cert,issuer,ids) == 0 ) + goto free_req; + + /* create the BIO with the request to send */ + bio_req = serialize_request(ocsp_req, hostname, port, path); + if (bio_req == NULL) { + goto free_req; + } + + apr_sock = make_socket(hostname, port, mp); + if (apr_sock == NULL) { + ocsp_resp = NULL; + goto free_bio; + } + + ok = ocsp_send_req(apr_sock, bio_req); + if (ok) + ocsp_resp = ocsp_get_resp(apr_sock); + +free_bio: + BIO_free(bio_req); + +free_req: + if(apr_sock && ok) /* if ok == 0 we have already closed the socket */ + apr_socket_close(apr_sock); + + apr_pool_destroy(mp); + + sk_OCSP_CERTID_free(ids); + OCSP_REQUEST_free(ocsp_req); + +end: + return ocsp_resp; +} + +/* Process the OCSP_RESPONSE and returns the corresponding + answert according to the status. +*/ +static int process_ocsp_response(OCSP_RESPONSE *ocsp_resp) +{ + int r, o = V_OCSP_CERTSTATUS_UNKNOWN, i; + OCSP_BASICRESP *bs; + OCSP_SINGLERESP *ss; + + r = OCSP_response_status(ocsp_resp); + + if (r != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + OCSP_RESPONSE_free(ocsp_resp); + return OCSP_STATUS_UNKNOWN; + } + bs = OCSP_response_get1_basic(ocsp_resp); + + ss = OCSP_resp_get0(bs,0); /* we know we have only 1 request */ + + i = OCSP_single_get0_status(ss, NULL, NULL, NULL, NULL); + if (i == V_OCSP_CERTSTATUS_GOOD) + o = OCSP_STATUS_OK; + else if (i == V_OCSP_CERTSTATUS_REVOKED) + o = OCSP_STATUS_REVOKED; + else if (i == V_OCSP_CERTSTATUS_UNKNOWN) + o = OCSP_STATUS_UNKNOWN; + + /* we clean up */ + OCSP_RESPONSE_free(ocsp_resp); + return o; +} + + +int SSL_ocsp_request(X509 *cert, X509 *issuer) +{ + char **ocsp_urls = NULL; + int nid, i; + X509_EXTENSION *ext; + ASN1_OCTET_STRING *os; + + apr_pool_t *p; + + apr_pool_create(&p, NULL); + + /* Get the proper extension */ + nid = X509_get_ext_by_NID(cert,NID_info_access,-1); + if (nid >= 0 ) { + ext = X509_get_ext(cert,nid); + os = X509_EXTENSION_get_data(ext); + + ocsp_urls = decode_OCSP_url(os, p); + } + + /* if we find the extensions and we can parse it check + the ocsp status. Otherwise, return OCSP_STATUS_UNKNOWN */ + if (ocsp_urls != NULL) { + OCSP_RESPONSE *resp; + /* for the time being just check for the fist response .. a better + approach is to iterate for all the possible ocsp urls */ + resp = get_ocsp_response(cert, issuer, ocsp_urls[0]); + + apr_pool_destroy(p); + if (resp != NULL) + return process_ocsp_response(resp); + } + apr_pool_destroy(p); + return OCSP_STATUS_UNKNOWN; +} + +#endif /* HAS_OCSP_ENABLED */ +#endif /* HAVE_OPENSSL */ Modified: tomcat/native/branches/1.1.x/xdocs/miscellaneous/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/native/branches/1.1.x/xdocs/miscellaneous/changelog.xml?rev=1293119&r1=1293118&r2=1293119&view=diff ============================================================================== --- tomcat/native/branches/1.1.x/xdocs/miscellaneous/changelog.xml (original) +++ tomcat/native/branches/1.1.x/xdocs/miscellaneous/changelog.xml Fri Feb 24 07:43:44 2012 @@ -38,6 +38,10 @@
+ + 45392: Add support for OCSP verification. Based upon a patch + from Aristotelis. (mturk) + 52119: Autodetect Diablo JDK on FreeBSD and Java7+. Based upon a patch from Michael Osipov. (mturk) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org