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 <openssl/bio.h>
+#include <openssl/ocsp.h>
+/* 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 @@
</section>
<section name="Changes between 1.1.22 and 1.1.23">
<changelog>
+ <update>
+ <bug>45392</bug>: Add support for OCSP verification. Based upon a patch
+ from Aristotelis. (mturk)
+ </update>
<fix>
<bug>52119</bug>: Autodetect Diablo JDK on FreeBSD and Java7+. Based
upon a patch
from Michael Osipov. (mturk)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]