From: Brian Pane Date: Thu, 6 Oct 2005 06:11:43 +0000 (+0000) Subject: forward-port the latest versions of mod_ssl and mod_setenvif from the 2.3 trunk to... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=64dbc48fe26b9bfe88956fd29ecc2542b5f75a0c;p=thirdparty%2Fapache%2Fhttpd.git forward-port the latest versions of mod_ssl and mod_setenvif from the 2.3 trunk to the async-dev branch so t/TEST will work once again git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/async-dev@306538 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c index f4ca7207b2a..d0f485fac19 100644 --- a/modules/metadata/mod_mime_magic.c +++ b/modules/metadata/mod_mime_magic.c @@ -947,16 +947,16 @@ static int apprentice(server_rec *s, apr_pool_t *p) /* parse it */ for (lineno = 1; apr_file_gets(line, BUFSIZ, f) == APR_SUCCESS; lineno++) { int ws_offset; - char *last = line + strlen(line) - 1; /* guaranteed that len >= 1 */ + char *last = line + strlen(line) - 1; /* guaranteed that len >= 1 since an + * "empty" line contains a '\n' + */ - /* delete newline and potential carriage return */ - if (*last == '\n') { + /* delete newline and any other trailing whitespace */ + while (last >= line + && apr_isspace(*last)) { *last = '\0'; --last; } - if (*last == '\r') { - *last = '\0'; - } /* skip leading whitespace */ ws_offset = 0; diff --git a/modules/metadata/mod_setenvif.c b/modules/metadata/mod_setenvif.c index 2d568cc0fc9..b2549d8e3b7 100644 --- a/modules/metadata/mod_setenvif.c +++ b/modules/metadata/mod_setenvif.c @@ -123,7 +123,7 @@ typedef struct { module AP_MODULE_DECLARE_DATA setenvif_module; -static APR_OPTIONAL_FN_TYPE(ssl_extlist_by_oid) *ssl_extlist_by_oid_func = NULL; +static APR_OPTIONAL_FN_TYPE(ssl_ext_list) *ssl_ext_list_func = NULL; /* * These routines, the create- and merge-config functions, are called @@ -531,7 +531,7 @@ static int match_headers(request_rec *r) break; case SPECIAL_OID_VALUE: /* If mod_ssl is not loaded, the accessor function is NULL */ - if (ssl_extlist_by_oid_func != NULL) + if (ssl_ext_list_func != NULL) { apr_array_header_t *oid_array; char **oid_value; @@ -539,7 +539,8 @@ static int match_headers(request_rec *r) char *retval = NULL; /* The given oid can occur multiple times. Concatenate the values */ - if ((oid_array = ssl_extlist_by_oid_func(r, b->name)) != NULL) { + if ((oid_array = ssl_ext_list_func(r->pool, r->connection, 1, + b->name)) != NULL) { oid_value = (char **) oid_array->elts; /* pass 1: determine the size of the string */ for (len=j=0; j < oid_array->nelts; j++) { @@ -630,7 +631,7 @@ static int match_headers(request_rec *r) static int setenvif_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { - ssl_extlist_by_oid_func = APR_RETRIEVE_OPTIONAL_FN(ssl_extlist_by_oid); + ssl_ext_list_func = APR_RETRIEVE_OPTIONAL_FN(ssl_ext_list); return OK; } diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index 5829947bd45..01a851c66dd 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -504,8 +504,6 @@ static void ssl_register_hooks(apr_pool_t *p) APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); - - APR_REGISTER_OPTIONAL_FN(ssl_extlist_by_oid); } module AP_MODULE_DECLARE_DATA ssl_module = { diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h index fa3253c53c6..5dff0c5d5a3 100644 --- a/modules/ssl/mod_ssl.h +++ b/modules/ssl/mod_ssl.h @@ -36,15 +36,20 @@ APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup, conn_rec *, request_rec *, char *)); -/** The ssl_ext_lookup() optional function retrieves the value of a SSL - * certificate X.509 extension. The client certificate is used if - * peer is non-zero; the server certificate is used otherwise. The - * oidnum parameter specifies the numeric OID (e.g. "1.2.3.4") of the - * desired extension. The string value of the extension is returned, - * or NULL on error. */ -APR_DECLARE_OPTIONAL_FN(const char *, ssl_ext_lookup, +/** The ssl_ext_list() optional function attempts to build an array + * of all the values contained in the named X.509 extension. The + * returned array will be created in the supplied pool. + * The client certificate is used if peer is non-zero; the server + * certificate is used otherwise. + * Extension specifies the extensions to use as a string. This can be + * one of the "known" long or short names, or a numeric OID, + * e.g. "1.2.3.4", 'nsComment' and 'DN' are all valid. + * A pointer to an apr_array_header_t structure is returned if at + * least one matching extension is found, NULL otherwise. + */ +APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_ext_list, (apr_pool_t *p, conn_rec *c, int peer, - const char *oidnum)); + const char *extension)); /** An optional function which returns non-zero if the given connection * is using SSL/TLS. */ @@ -58,7 +63,5 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); -APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_extlist_by_oid, (request_rec *r, const char *oidstr)); - #endif /* __MOD_SSL_H__ */ /** @} */ diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index 1a14701c141..996c35abb6f 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -882,6 +882,7 @@ static apr_status_t ssl_io_filter_error(ap_filter_t *f, } static const char ssl_io_filter[] = "SSL/TLS Filter"; +static const char ssl_io_buffer[] = "SSL/TLS Buffer"; /* * Close the SSL part of the socket connection @@ -1446,6 +1447,187 @@ static apr_status_t ssl_io_filter_output(ap_filter_t *f, return status; } +/* 128K maximum buffer size by default. */ +#ifndef SSL_MAX_IO_BUFFER +#define SSL_MAX_IO_BUFFER (128 * 1024) +#endif + +struct modssl_buffer_ctx { + apr_bucket_brigade *bb; + apr_pool_t *pool; +}; + +int ssl_io_buffer_fill(request_rec *r) +{ + conn_rec *c = r->connection; + struct modssl_buffer_ctx *ctx; + apr_bucket_brigade *tempb; + apr_off_t total = 0; /* total length buffered */ + int eos = 0; /* non-zero once EOS is seen */ + + /* Create the context which will be passed to the input filter; + * containing a setaside pool and a brigade which constrain the + * lifetime of the buffered data. */ + ctx = apr_palloc(r->pool, sizeof *ctx); + apr_pool_create(&ctx->pool, r->pool); + ctx->bb = apr_brigade_create(ctx->pool, c->bucket_alloc); + + /* ... and a temporary brigade. */ + tempb = apr_brigade_create(r->pool, c->bucket_alloc); + + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "filling buffer"); + + do { + apr_status_t rv; + apr_bucket *e, *next; + + /* The request body is read from the protocol-level input + * filters; the buffering filter will reinject it from that + * level, allowing content/resource filters to run later, if + * necessary. */ + + rv = ap_get_brigade(r->proto_input_filters, tempb, AP_MODE_READBYTES, + APR_BLOCK_READ, 8192); + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "could not read request body for SSL buffer"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* Iterate through the returned brigade: setaside each bucket + * into the context's pool and move it into the brigade. */ + for (e = APR_BRIGADE_FIRST(tempb); + e != APR_BRIGADE_SENTINEL(tempb) && !eos; e = next) { + const char *data; + apr_size_t len; + + next = APR_BUCKET_NEXT(e); + + if (APR_BUCKET_IS_EOS(e)) { + eos = 1; + } else if (!APR_BUCKET_IS_METADATA(e)) { + rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "could not read bucket for SSL buffer"); + return HTTP_INTERNAL_SERVER_ERROR; + } + total += len; + } + + rv = apr_bucket_setaside(e, ctx->pool); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "could not setaside bucket for SSL buffer"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + APR_BUCKET_REMOVE(e); + APR_BRIGADE_INSERT_TAIL(ctx->bb, e); + } + + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, + "total of %" APR_OFF_T_FMT " bytes in buffer, eos=%d", + total, eos); + + /* Fail if this exceeds the maximum buffer size. */ + if (total > SSL_MAX_IO_BUFFER) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "request body exceeds maximum size for SSL buffer"); + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + + } while (!eos); + + apr_brigade_destroy(tempb); + + /* Insert the filter which will supply the buffered data. */ + ap_add_input_filter(ssl_io_buffer, ctx, r, c); + + return 0; +} + +/* This input filter supplies the buffered request body to the caller + * from the brigade stored in f->ctx. */ +static apr_status_t ssl_io_filter_buffer(ap_filter_t *f, + apr_bucket_brigade *bb, + ap_input_mode_t mode, + apr_read_type_e block, + apr_off_t bytes) +{ + struct modssl_buffer_ctx *ctx = f->ctx; + apr_status_t rv; + + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, + "read from buffered SSL brigade, mode %d, " + "%" APR_OFF_T_FMT " bytes", + mode, bytes); + + if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { + return APR_ENOTIMPL; + } + + if (mode == AP_MODE_READBYTES) { + apr_bucket *e; + + /* Partition the buffered brigade. */ + rv = apr_brigade_partition(ctx->bb, bytes, &e); + if (rv && rv != APR_INCOMPLETE) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, + "could not partition buffered SSL brigade"); + ap_remove_input_filter(f); + return rv; + } + + /* If the buffered brigade contains less then the requested + * length, just pass it all back. */ + if (rv == APR_INCOMPLETE) { + APR_BRIGADE_CONCAT(bb, ctx->bb); + } else { + apr_bucket *d = APR_BRIGADE_FIRST(ctx->bb); + + e = APR_BUCKET_PREV(e); + + /* Unsplice the partitioned segment and move it into the + * passed-in brigade; no convenient way to do this with + * the APR_BRIGADE_* macros. */ + APR_RING_UNSPLICE(d, e, link); + APR_RING_SPLICE_HEAD(&bb->list, d, e, apr_bucket, link); + + APR_BRIGADE_CHECK_CONSISTENCY(bb); + APR_BRIGADE_CHECK_CONSISTENCY(ctx->bb); + } + } + else { + /* Split a line into the passed-in brigade. */ + rv = apr_brigade_split_line(bb, ctx->bb, mode, bytes); + + if (rv) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, + "could not split line from buffered SSL brigade"); + ap_remove_input_filter(f); + return rv; + } + } + + if (APR_BRIGADE_EMPTY(ctx->bb)) { + apr_bucket *e = APR_BRIGADE_LAST(bb); + + /* Ensure that the brigade is terminated by an EOS if the + * buffered request body has been entirely consumed. */ + if (e == APR_BRIGADE_SENTINEL(bb) || !APR_BUCKET_IS_EOS(e)) { + e = apr_bucket_eos_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, e); + } + + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, + "buffered SSL brigade now exhausted; removing filter"); + ap_remove_input_filter(f); + } + + return APR_SUCCESS; +} + static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c, SSL *ssl) { @@ -1508,6 +1690,9 @@ void ssl_io_filter_register(apr_pool_t *p) ap_register_input_filter (ssl_io_filter, ssl_io_filter_input, NULL, AP_FTYPE_CONNECTION + 5); ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5); + + ap_register_input_filter (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL - 1); + return; } diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index 02ee92a806b..032e1424751 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -490,73 +490,35 @@ int ssl_hook_Access(request_rec *r) } #endif /* HAVE_SSL_SET_CERT_STORE */ - /* - * SSL renegotiations in conjunction with HTTP - * requests using the POST method are not supported. - * - * Background: - * - * 1. When the client sends a HTTP/HTTPS request, Apache's core code - * reads only the request line ("METHOD /path HTTP/x.y") and the - * attached MIME headers ("Foo: bar") up to the terminating line ("CR - * LF"). An attached request body (for instance the data of a POST - * method) is _NOT_ read. Instead it is read by mod_cgi's content - * handler and directly passed to the CGI script. - * - * 2. mod_ssl supports per-directory re-configuration of SSL parameters. - * This is implemented by performing an SSL renegotiation of the - * re-configured parameters after the request is read, but before the - * response is sent. In more detail: the renegotiation happens after the - * request line and MIME headers were read, but _before_ the attached - * request body is read. The reason simply is that in the HTTP protocol - * usually there is no acknowledgment step between the headers and the - * body (there is the 100-continue feature and the chunking facility - * only), so Apache has no API hook for this step. - * - * 3. the problem now occurs when the client sends a POST request for - * URL /foo via HTTPS the server and the server has SSL parameters - * re-configured on a per-URL basis for /foo. Then mod_ssl has to - * perform an SSL renegotiation after the request was read and before - * the response is sent. But the problem is the pending POST body data - * in the receive buffer of SSL (which Apache still has not read - it's - * pending until mod_cgi sucks it in). When mod_ssl now tries to perform - * the renegotiation the pending data leads to an I/O error. - * - * Solution Idea: - * - * There are only two solutions: Either to simply state that POST - * requests to URLs with SSL re-configurations are not allowed, or to - * renegotiate really after the _complete_ request (i.e. including - * the POST body) was read. Obviously the latter would be preferred, - * but it cannot be done easily inside Apache, because as already - * mentioned, there is no API step between the body reading and the body - * processing. And even when we mod_ssl would hook directly into the - * loop of mod_cgi, we wouldn't solve the problem for other handlers, of - * course. So the only general solution is to suck in the pending data - * of the request body from the OpenSSL BIO into the Apache BUFF. Then - * the renegotiation can be done and after this step Apache can proceed - * processing the request as before. - * - * Solution Implementation: - * - * We cannot simply suck in the data via an SSL_read-based loop because of - * HTTP chunking. Instead we _have_ to use the Apache API for this step which - * is aware of HTTP chunking. So the trick is to suck in the pending request - * data via the Apache API (which uses Apache's BUFF code and in the - * background mod_ssl's I/O glue code) and re-inject it later into the Apache - * BUFF code again. This way the data flows twice through the Apache BUFF, of - * course. But this way the solution doesn't depend on any Apache specifics - * and is fully transparent to Apache modules. - * - * !! BUT ALL THIS IS STILL NOT RE-IMPLEMENTED FOR APACHE 2.0 !! + /* If a renegotiation is now required for this location, and the + * request includes a message body (and the client has not + * requested a "100 Continue" response), then the client will be + * streaming the request body over the wire already. In that + * case, it is not possible to stop and perform a new SSL + * handshake immediately; once the SSL library moves to the + * "accept" state, it will reject the SSL packets which the client + * is sending for the request body. + * + * To allow authentication to complete in this auth hook, the + * solution used here is to fill a (bounded) buffer with the + * request body, and then to reinject that request body later. */ - if (renegotiate && !renegotiate_quick && (r->method_number == M_POST)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "SSL Re-negotiation in conjunction " - "with POST method not supported! " - "hint: try SSLOptions +OptRenegotiate"); - - return HTTP_METHOD_NOT_ALLOWED; + if (renegotiate && !renegotiate_quick + && (apr_table_get(r->headers_in, "transfer-encoding") + || (apr_table_get(r->headers_in, "content-length") + && strcmp(apr_table_get(r->headers_in, "content-length"), "0"))) + && !r->expecting_100) { + int rv; + + /* Fill the I/O buffer with the request body if possible. */ + rv = ssl_io_buffer_fill(r); + + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "could not buffer message body to allow " + "SSL renegotiation to proceed"); + return rv; + } } /* @@ -753,6 +715,9 @@ int ssl_hook_Access(request_rec *r) r, (char *)dc->szUserName); if (val && val[0]) r->user = val; + else + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + "Failed to set r->user to '%s'", dc->szUserName); } /* diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index ca505f87bbb..5f1f571096e 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -62,7 +62,7 @@ void ssl_var_register(void) { APR_REGISTER_OPTIONAL_FN(ssl_is_https); APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); - APR_REGISTER_OPTIONAL_FN(ssl_ext_lookup); + APR_REGISTER_OPTIONAL_FN(ssl_ext_list); return; } @@ -431,8 +431,9 @@ static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char * n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) { - result = apr_pstrmemdup(p, - X509_NAME_ENTRY_get_data_ptr(xsne), + unsigned char *data = X509_NAME_ENTRY_get_data_ptr(xsne); + /* cast needed from unsigned char to char */ + result = apr_pstrmemdup(p, (char *)data, X509_NAME_ENTRY_get_data_len(xsne)); #if APR_CHARSET_EBCDIC ap_xlate_proto_from_ascii(result, X509_NAME_ENTRY_get_data_len(xsne)); @@ -660,23 +661,30 @@ static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var) return result; } -const char *ssl_ext_lookup(apr_pool_t *p, conn_rec *c, int peer, - const char *oidnum) +apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer, + const char *extension) { SSLConnRec *sslconn = myConnConfig(c); - SSL *ssl; + SSL *ssl = NULL; + apr_array_header_t *array = NULL; X509 *xs = NULL; - ASN1_OBJECT *oid; + ASN1_OBJECT *oid = NULL; int count = 0, j; - char *result = NULL; - - if (!sslconn || !sslconn->ssl) { + + if (!sslconn || !sslconn->ssl || !extension) { return NULL; } ssl = sslconn->ssl; - oid = OBJ_txt2obj(oidnum, 1); + /* We accept the "extension" string to be converted as + * a long name (nsComment), short name (DN) or + * numeric OID (1.2.3.4). + */ + oid = OBJ_txt2obj(extension, 0); if (!oid) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, + "Failed to create an object for extension '%s'", + extension); ERR_clear_error(); return NULL; } @@ -685,34 +693,50 @@ const char *ssl_ext_lookup(apr_pool_t *p, conn_rec *c, int peer, if (xs == NULL) { return NULL; } - - count = X509_get_ext_count(xs); + count = X509_get_ext_count(xs); + /* Create an array large enough to accomodate every extension. This is + * likely overkill, but safe. + */ + array = apr_array_make(p, count, sizeof(char *)); for (j = 0; j < count; j++) { X509_EXTENSION *ext = X509_get_ext(xs, j); if (OBJ_cmp(ext->object, oid) == 0) { BIO *bio = BIO_new(BIO_s_mem()); - if (X509V3_EXT_print(bio, ext, 0, 0) == 1) { + /* We want to obtain a string representation of the extensions + * value and add it to the array we're building. + * X509V3_EXT_print() doesn't know about all the possible + * data types, but the value is stored as an ASN1_OCTET_STRING + * allowing us a fallback in case of X509V3_EXT_print + * not knowing how to handle the data. + */ + if (X509V3_EXT_print(bio, ext, 0, 0) == 1 || + ASN1_STRING_print(bio, ext->value) == 1) { BUF_MEM *buf; - + char **ptr = apr_array_push(array); BIO_get_mem_ptr(bio, &buf); - result = apr_pstrmemdup(p, buf->data, buf->length); + *ptr = apr_pstrmemdup(p, buf->data, buf->length); + } else { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, + "Found an extension '%s', but failed to " + "create a string from it", extension); } - BIO_vfree(bio); - break; } } + if (array->nelts == 0) + array = NULL; + if (peer) { /* only SSL_get_peer_certificate raises the refcount */ X509_free(xs); } ERR_clear_error(); - return result; + return array; } static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl) diff --git a/modules/ssl/ssl_expr.h b/modules/ssl/ssl_expr.h index 6f276475ba5..b73b305c681 100644 --- a/modules/ssl/ssl_expr.h +++ b/modules/ssl/ssl_expr.h @@ -68,7 +68,7 @@ #endif typedef enum { - op_NOP, op_ListElement, op_OidListElement, + op_NOP, op_ListElement, op_PeerExtElement, op_True, op_False, op_Not, op_Or, op_And, op_Comp, op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE, op_IN, op_REG, op_NRE, op_Digit, op_String, op_Regex, op_Var, op_Func diff --git a/modules/ssl/ssl_expr_eval.c b/modules/ssl/ssl_expr_eval.c index e40df2dccbb..76e0107fc0b 100644 --- a/modules/ssl/ssl_expr_eval.c +++ b/modules/ssl/ssl_expr_eval.c @@ -118,7 +118,7 @@ static BOOL ssl_expr_eval_comp(request_rec *r, ssl_expr *node) e3 = (ssl_expr *)e2->node_arg1; e2 = (ssl_expr *)e2->node_arg2; - if (op == op_OidListElement) { + if (op == op_PeerExtElement) { char *w3 = ssl_expr_eval_word(r, e3); found = ssl_expr_eval_oid(r, w1, w3); @@ -198,63 +198,6 @@ static char *ssl_expr_eval_word(request_rec *r, ssl_expr *node) } } -#define NUM_OID_ELTS 8 /* start with 8 oid slots, resize when needed */ - -apr_array_header_t *ssl_extlist_by_oid(request_rec *r, const char *oidstr) -{ - int count = 0, j; - X509 *xs = NULL; - ASN1_OBJECT *oid; - apr_array_header_t *val_array; - SSLConnRec *sslconn = myConnConfig(r->connection); - - /* trivia */ - if (oidstr == NULL || sslconn == NULL || sslconn->ssl == NULL) - return NULL; - - /* Determine the oid we are looking for */ - if ((oid = OBJ_txt2obj(oidstr, 1)) == NULL) { - ERR_clear_error(); - return NULL; - } - - /* are there any extensions in the cert? */ - if ((xs = SSL_get_peer_certificate(sslconn->ssl)) == NULL || - (count = X509_get_ext_count(xs)) == 0) { - return NULL; - } - - val_array = apr_array_make(r->pool, NUM_OID_ELTS, sizeof(char *)); - - /* Loop over all extensions, extract the desired oids */ - for (j = 0; j < count; j++) { - X509_EXTENSION *ext = X509_get_ext(xs, j); - - if (OBJ_cmp(ext->object, oid) == 0) { - BIO *bio = BIO_new(BIO_s_mem()); - - if (X509V3_EXT_print(bio, ext, 0, 0) == 1) { - BUF_MEM *buf; - char **new = apr_array_push(val_array); - - BIO_get_mem_ptr(bio, &buf); - - *new = apr_pstrdup(r->pool, buf->data); - } - - BIO_vfree(bio); - } - } - - X509_free(xs); - ERR_clear_error(); - - if (val_array->nelts == 0) - return NULL; - else - return val_array; -} - static BOOL ssl_expr_eval_oid(request_rec *r, const char *word, const char *oidstr) { int j; @@ -262,7 +205,7 @@ static BOOL ssl_expr_eval_oid(request_rec *r, const char *word, const char *oids apr_array_header_t *oid_array; char **oid_value; - if (NULL == (oid_array = ssl_extlist_by_oid(r, oidstr))) { + if (NULL == (oid_array = ssl_ext_list(r->pool, r->connection, 1, oidstr))) { return FALSE; } diff --git a/modules/ssl/ssl_expr_parse.c b/modules/ssl/ssl_expr_parse.c index 9df1389dd67..ee172a78e1c 100644 --- a/modules/ssl/ssl_expr_parse.c +++ b/modules/ssl/ssl_expr_parse.c @@ -43,7 +43,7 @@ typedef union { #define T_OP_REG 271 #define T_OP_NRE 272 #define T_OP_IN 273 -#define T_OP_OID 274 +#define T_OP_PEEREXTLIST 274 #define T_OP_OR 275 #define T_OP_AND 276 #define T_OP_NOT 277 @@ -164,7 +164,7 @@ const char * const ssl_expr_yyname[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"T_TRUE", "T_FALSE","T_DIGIT","T_ID","T_STRING","T_REGEX","T_REGEX_I","T_FUNC_FILE", "T_OP_EQ","T_OP_NE","T_OP_LT","T_OP_LE","T_OP_GT","T_OP_GE","T_OP_REG", -"T_OP_NRE","T_OP_IN","T_OP_OID","T_OP_OR","T_OP_AND","T_OP_NOT", +"T_OP_NRE","T_OP_IN","T_OP_PEEREXTLIST","T_OP_OR","T_OP_AND","T_OP_NOT", }; const char * const ssl_expr_yyrule[] = { "$accept : root", @@ -185,7 +185,7 @@ const char * const ssl_expr_yyrule[] = { "comparison : word T_OP_IN wordlist", "comparison : word T_OP_REG regex", "comparison : word T_OP_NRE regex", -"wordlist : T_OP_OID '(' word ')'", +"wordlist : T_OP_PEEREXTLIST '(' word ')'", "wordlist : '{' words '}'", "words : word", "words : words ',' word", @@ -498,7 +498,7 @@ case 17: break; case 18: #line 107 "ssl_expr_parse.y" -{ ssl_expr_yyval.exVal = ssl_expr_make(op_OidListElement, ssl_expr_yyvsp[-1].exVal, NULL); } +{ ssl_expr_yyval.exVal = ssl_expr_make(op_PeerExtElement, ssl_expr_yyvsp[-1].exVal, NULL); } break; case 19: #line 108 "ssl_expr_parse.y" diff --git a/modules/ssl/ssl_expr_parse.h b/modules/ssl/ssl_expr_parse.h index 66952eb138b..8b15f6151a5 100644 --- a/modules/ssl/ssl_expr_parse.h +++ b/modules/ssl/ssl_expr_parse.h @@ -19,7 +19,7 @@ #define T_OP_REG 271 #define T_OP_NRE 272 #define T_OP_IN 273 -#define T_OP_OID 274 +#define T_OP_PEEREXTLIST 274 #define T_OP_OR 275 #define T_OP_AND 276 #define T_OP_NOT 277 diff --git a/modules/ssl/ssl_expr_parse.y b/modules/ssl/ssl_expr_parse.y index 9c641e13139..90da88aea96 100644 --- a/modules/ssl/ssl_expr_parse.y +++ b/modules/ssl/ssl_expr_parse.y @@ -61,7 +61,7 @@ %token T_OP_REG %token T_OP_NRE %token T_OP_IN -%token T_OP_OID +%token T_OP_PEEREXTLIST %token T_OP_OR %token T_OP_AND @@ -104,7 +104,7 @@ comparison: word T_OP_EQ word { $$ = ssl_expr_make(op_EQ, $1, $3); } | word T_OP_NRE regex { $$ = ssl_expr_make(op_NRE, $1, $3); } ; -wordlist : T_OP_OID '(' word ')' { $$ = ssl_expr_make(op_OidListElement, $3, NULL); } +wordlist : T_OP_PEEREXTLIST '(' word ')' { $$ = ssl_expr_make(op_PeerExtElement, $3, NULL); } | '{' words '}' { $$ = $2 ; } ; diff --git a/modules/ssl/ssl_expr_scan.c b/modules/ssl/ssl_expr_scan.c index ddcd1665932..07a9be1b41a 100644 --- a/modules/ssl/ssl_expr_scan.c +++ b/modules/ssl/ssl_expr_scan.c @@ -304,7 +304,7 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); #define YY_NUM_RULES 47 #define YY_END_OF_BUFFER 48 -static yyconst short int yy_accept[89] = +static yyconst short int yy_accept[97] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 46, 1, 38, 2, 46, 44, 24, 46, 28, 45, 45, @@ -313,8 +313,10 @@ static yyconst short int yy_accept[89] = 32, 34, 44, 26, 20, 31, 30, 45, 45, 45, 19, 45, 45, 29, 27, 39, 25, 23, 15, 15, 21, 45, 35, 45, 36, 13, 12, 5, 6, 10, - 11, 7, 8, 9, 40, 33, 45, 45, 37, 45, - 5, 6, 45, 41, 42, 5, 43, 0 + 11, 7, 8, 9, 45, 33, 45, 45, 37, 45, + 5, 6, 45, 45, 41, 42, 5, 45, 43, 45, + 45, 45, 45, 45, 40, 0 + } ; static yyconst int yy_ec[256] = @@ -325,14 +327,14 @@ static yyconst int yy_ec[256] = 1, 2, 4, 5, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 7, 1, 1, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 7, 1, 10, - 11, 12, 1, 1, 13, 13, 13, 14, 13, 13, - 13, 13, 15, 13, 13, 13, 13, 13, 16, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 1, 17, 1, 1, 7, 1, 18, 19, 13, 20, - - 21, 22, 23, 13, 24, 13, 13, 25, 26, 27, - 28, 13, 29, 30, 31, 32, 33, 13, 13, 13, - 13, 13, 1, 34, 1, 35, 1, 1, 1, 1, + 11, 12, 1, 1, 13, 13, 13, 13, 14, 13, + 13, 13, 15, 13, 13, 16, 13, 13, 13, 17, + 13, 18, 19, 20, 13, 13, 13, 21, 13, 13, + 1, 22, 1, 1, 7, 1, 23, 24, 13, 25, + + 26, 27, 28, 13, 29, 13, 13, 30, 31, 32, + 33, 17, 34, 35, 36, 37, 38, 13, 13, 21, + 13, 13, 1, 39, 1, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -349,90 +351,100 @@ static yyconst int yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst int yy_meta[36] = +static yyconst int yy_meta[41] = { 0, 1, 1, 2, 1, 3, 1, 4, 4, 4, 1, - 1, 1, 4, 4, 4, 4, 3, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 1, 1 + 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 1, 1 } ; -static yyconst short int yy_base[96] = +static yyconst short int yy_base[104] = { 0, - 0, 0, 33, 34, 0, 0, 88, 87, 110, 154, - 38, 31, 154, 103, 35, 97, 34, 96, 0, 31, - 75, 72, 29, 27, 73, 28, 69, 33, 48, 69, - 64, 0, 154, 154, 97, 154, 154, 154, 54, 154, - 154, 154, 56, 154, 154, 154, 154, 0, 38, 77, - 0, 71, 70, 0, 0, 0, 0, 0, 154, 0, - 0, 62, 0, 60, 154, 0, 154, 59, 68, 154, - 154, 154, 154, 154, 0, 0, 61, 70, 0, 69, - 74, 76, 68, 0, 0, 79, 0, 154, 129, 133, - 137, 58, 141, 145, 149 - + 0, 0, 38, 39, 0, 0, 101, 100, 128, 174, + 43, 36, 174, 121, 40, 115, 39, 114, 0, 37, + 92, 89, 29, 27, 90, 28, 79, 29, 82, 81, + 76, 0, 174, 174, 112, 174, 174, 174, 54, 174, + 174, 174, 58, 174, 174, 174, 174, 0, 45, 87, + 0, 81, 80, 0, 0, 0, 0, 0, 174, 0, + 0, 71, 0, 69, 174, 0, 174, 60, 64, 174, + 174, 174, 174, 174, 52, 0, 70, 79, 0, 78, + 66, 69, 68, 74, 0, 0, 84, 78, 0, 66, + 72, 80, 77, 77, 0, 174, 149, 153, 157, 94, + + 161, 165, 169 } ; -static yyconst short int yy_def[96] = +static yyconst short int yy_def[104] = { 0, - 88, 1, 89, 89, 90, 90, 91, 91, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 92, 92, - 92, 92, 92, 92, 92, 92, 93, 92, 92, 92, - 88, 94, 88, 88, 95, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 88, 92, - 92, 92, 92, 92, 88, 94, 88, 88, 88, 88, - 88, 88, 88, 88, 92, 92, 92, 92, 92, 92, - 88, 88, 92, 92, 92, 88, 92, 0, 88, 88, - 88, 88, 88, 88, 88 - + 96, 1, 97, 97, 98, 98, 99, 99, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 100, 100, + 100, 100, 100, 100, 100, 100, 101, 100, 100, 100, + 96, 102, 96, 96, 103, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 96, 100, + 100, 100, 100, 100, 96, 102, 96, 96, 96, 96, + 96, 96, 96, 96, 100, 100, 100, 100, 100, 100, + 96, 96, 100, 100, 100, 100, 96, 100, 100, 100, + 100, 100, 100, 100, 100, 0, 96, 96, 96, 96, + + 96, 96, 96 } ; -static yyconst short int yy_nxt[190] = +static yyconst short int yy_nxt[215] = { 0, 10, 11, 11, 12, 13, 14, 10, 15, 15, 16, - 17, 18, 19, 19, 19, 20, 10, 21, 19, 19, - 22, 23, 24, 25, 26, 27, 28, 29, 19, 19, - 19, 30, 19, 31, 10, 33, 33, 34, 34, 39, - 39, 40, 43, 43, 45, 49, 52, 54, 57, 35, - 35, 75, 53, 61, 49, 39, 39, 75, 55, 58, - 62, 48, 49, 43, 43, 41, 81, 82, 46, 59, - 59, 49, 59, 59, 59, 82, 82, 63, 59, 59, - 59, 86, 82, 82, 82, 59, 82, 82, 87, 85, - 84, 83, 80, 79, 78, 77, 76, 65, 64, 56, - - 51, 50, 59, 59, 68, 69, 47, 44, 42, 88, - 38, 38, 88, 88, 88, 70, 88, 88, 71, 88, - 88, 88, 88, 72, 88, 88, 73, 88, 74, 32, + 17, 18, 19, 19, 19, 19, 20, 19, 19, 19, + 19, 10, 21, 19, 19, 22, 23, 24, 25, 26, + 27, 28, 29, 19, 19, 19, 30, 19, 31, 10, + 33, 33, 34, 34, 39, 39, 40, 43, 43, 45, + 49, 52, 54, 57, 61, 39, 39, 53, 75, 35, + 35, 62, 49, 55, 58, 43, 43, 81, 82, 83, + 75, 82, 82, 87, 82, 41, 82, 82, 46, 59, + 59, 88, 59, 59, 59, 91, 83, 92, 59, 59, + 59, 82, 82, 88, 93, 94, 95, 48, 90, 89, + + 59, 92, 91, 86, 85, 84, 80, 79, 93, 78, + 77, 76, 94, 95, 65, 64, 63, 59, 59, 68, + 69, 56, 51, 50, 47, 44, 42, 96, 38, 38, + 96, 96, 96, 96, 96, 70, 96, 96, 71, 96, + 96, 96, 96, 72, 96, 96, 73, 96, 74, 32, 32, 32, 32, 36, 36, 36, 36, 37, 37, 37, - 37, 60, 88, 60, 60, 66, 88, 88, 66, 67, - 67, 67, 67, 9, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88 + 37, 60, 96, 60, 60, 66, 96, 96, 66, 67, + 67, 67, 67, 9, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96 } ; -static yyconst short int yy_chk[190] = +static yyconst short int yy_chk[215] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 4, 3, 4, 11, - 11, 12, 15, 15, 17, 20, 23, 24, 26, 3, - 4, 49, 23, 28, 20, 39, 39, 49, 24, 26, - 28, 92, 29, 43, 43, 12, 68, 68, 17, 27, - 27, 29, 27, 27, 27, 69, 69, 29, 27, 27, - 27, 81, 81, 82, 82, 27, 86, 86, 83, 80, - 78, 77, 64, 62, 53, 52, 50, 31, 30, 25, - - 22, 21, 27, 27, 35, 35, 18, 16, 14, 9, - 8, 7, 0, 0, 0, 35, 0, 0, 35, 0, - 0, 0, 0, 35, 0, 0, 35, 0, 35, 89, - 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, - 91, 93, 0, 93, 93, 94, 0, 0, 94, 95, - 95, 95, 95, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 4, 3, 4, 11, 11, 12, 15, 15, 17, + 20, 23, 24, 26, 28, 39, 39, 23, 49, 3, + 4, 28, 20, 24, 26, 43, 43, 68, 68, 75, + 49, 69, 69, 81, 81, 12, 82, 82, 17, 27, + 27, 83, 27, 27, 27, 90, 75, 91, 27, 27, + 27, 87, 87, 83, 92, 93, 94, 100, 88, 84, + + 27, 91, 90, 80, 78, 77, 64, 62, 92, 53, + 52, 50, 93, 94, 31, 30, 29, 27, 27, 35, + 35, 25, 22, 21, 18, 16, 14, 9, 8, 7, + 0, 0, 0, 0, 0, 35, 0, 0, 35, 0, + 0, 0, 0, 35, 0, 0, 35, 0, 35, 97, + 97, 97, 97, 98, 98, 98, 98, 99, 99, 99, + 99, 101, 0, 101, 101, 102, 0, 0, 102, 103, + 103, 103, 103, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96 } ; static yy_state_type yy_last_accepting_state; @@ -500,7 +512,7 @@ int yyinput(char *buf, int max_size); #define regex 2 #define regex_flags 3 -#line 505 "lex.ssl_expr_yy.c" +#line 517 "lex.ssl_expr_yy.c" /* Macros after this point can all be overridden by user definitions in * section 1. @@ -663,7 +675,7 @@ YY_DECL /* * Whitespaces */ -#line 668 "lex.ssl_expr_yy.c" +#line 680 "lex.ssl_expr_yy.c" if ( yy_init ) { @@ -714,13 +726,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 89 ) + if ( yy_current_state >= 97 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_current_state != 88 ); + while ( yy_current_state != 96 ); yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; @@ -1008,7 +1020,7 @@ YY_RULE_SETUP case 40: YY_RULE_SETUP #line 176 "ssl_expr_scan.l" -{ return T_OP_OID; } +{ return T_OP_PEEREXTLIST; } YY_BREAK /* * Functions @@ -1068,7 +1080,7 @@ YY_RULE_SETUP #line 212 "ssl_expr_scan.l" YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK -#line 1073 "lex.ssl_expr_yy.c" +#line 1085 "lex.ssl_expr_yy.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(str): case YY_STATE_EOF(regex): @@ -1363,7 +1375,7 @@ static yy_state_type yy_get_previous_state() while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 89 ) + if ( yy_current_state >= 97 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1398,11 +1410,11 @@ yy_state_type yy_current_state; while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 89 ) + if ( yy_current_state >= 97 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 88); + yy_is_jam = (yy_current_state == 96); return yy_is_jam ? 0 : yy_current_state; } diff --git a/modules/ssl/ssl_expr_scan.l b/modules/ssl/ssl_expr_scan.l index a54e09a130e..c5dffcdcdea 100644 --- a/modules/ssl/ssl_expr_scan.l +++ b/modules/ssl/ssl_expr_scan.l @@ -173,7 +173,7 @@ int yyinput(char *buf, int max_size); "not" { return T_OP_NOT; } "!" { return T_OP_NOT; } "in" { return T_OP_IN; } -[Oo][Ii][Dd] { return T_OP_OID; } +[Pp][Ee][Ee][Rr][Ee][Xx][Tt][Ll][Ii][Ss][Tt] { return T_OP_PEEREXTLIST; } /* * Functions diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index c48832dd757..2e8978140ff 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -595,6 +595,10 @@ void ssl_io_filter_init(conn_rec *, SSL *); void ssl_io_filter_register(apr_pool_t *); long ssl_io_data_cb(BIO *, int, MODSSL_BIO_CB_ARG_TYPE *, int, long, long); +/* ssl_io_buffer_fill fills the setaside buffering of the HTTP request + * to allow an SSL renegotiation to take place. */ +int ssl_io_buffer_fill(request_rec *r); + /** PRNG */ int ssl_rand_seed(server_rec *, apr_pool_t *, ssl_rsctx_t, char *); @@ -646,9 +650,7 @@ void ssl_log_ssl_error(const char *, int, int, server_rec *); /** Variables */ void ssl_var_register(void); char *ssl_var_lookup(apr_pool_t *, server_rec *, conn_rec *, request_rec *, char *); -const char *ssl_ext_lookup(apr_pool_t *p, conn_rec *c, int peer, const char *oid); - -extern apr_array_header_t *ssl_extlist_by_oid(request_rec *r, const char *oidstr); +apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer, const char *extension); void ssl_var_log_config_register(apr_pool_t *p); diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c index bd6c2c8e81e..edfcb09643d 100644 --- a/modules/ssl/ssl_util.c +++ b/modules/ssl/ssl_util.c @@ -137,10 +137,11 @@ BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p) ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) { ssl_algo_t t; + EVP_PKEY *pFreeKey = NULL; t = SSL_ALGO_UNKNOWN; if (pCert != NULL) - pKey = X509_get_pubkey(pCert); + pFreeKey = pKey = X509_get_pubkey(pCert); if (pKey != NULL) { switch (EVP_PKEY_key_type(pKey)) { case EVP_PKEY_RSA: @@ -153,6 +154,11 @@ ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) break; } } +#ifdef OPENSSL_VERSION_NUMBER + /* Only refcounted in OpenSSL */ + if (pFreeKey != NULL) + EVP_PKEY_free(pFreeKey); +#endif return t; }