summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/lib/apps.c33
-rw-r--r--crypto/http/http_client.c12
-rw-r--r--doc/man3/OSSL_HTTP_transfer.pod18
3 files changed, 42 insertions, 21 deletions
diff --git a/apps/lib/apps.c b/apps/lib/apps.c
index 88c4f7b97a..034fd45c4b 100644
--- a/apps/lib/apps.c
+++ b/apps/lib/apps.c
@@ -2462,7 +2462,7 @@ static const char *tls_error_hint(void)
}
/* HTTP callback function that supports TLS connection also via HTTPS proxy */
-BIO *app_http_tls_cb(BIO *hbio, void *arg, int connect, int detail)
+BIO *app_http_tls_cb(BIO *bio, void *arg, int connect, int detail)
{
if (connect && detail) { /* connecting with TLS */
APP_HTTP_TLS_INFO *info = (APP_HTTP_TLS_INFO *)arg;
@@ -2471,7 +2471,7 @@ BIO *app_http_tls_cb(BIO *hbio, void *arg, int connect, int detail)
BIO *sbio = NULL;
if ((info->use_proxy
- && !OSSL_HTTP_proxy_connect(hbio, info->server, info->port,
+ && !OSSL_HTTP_proxy_connect(bio, info->server, info->port,
NULL, NULL, /* no proxy credentials */
info->timeout, bio_err, opt_getprog()))
|| (sbio = BIO_new(BIO_f_ssl())) == NULL) {
@@ -2487,18 +2487,25 @@ BIO *app_http_tls_cb(BIO *hbio, void *arg, int connect, int detail)
SSL_set_connect_state(ssl);
BIO_set_ssl(sbio, ssl, BIO_CLOSE);
- hbio = BIO_push(sbio, hbio);
- } else if (!connect && !detail) { /* disconnecting after error */
- const char *hint = tls_error_hint();
-
- if (hint != NULL)
- ERR_add_error_data(2, " : ", hint);
- /*
- * If we pop sbio and BIO_free() it this may lead to libssl double free.
- * Rely on BIO_free_all() done by OSSL_HTTP_transfer() in http_client.c
- */
+ bio = BIO_push(sbio, bio);
}
- return hbio;
+ if (!connect) {
+ const char *hint;
+ BIO *cbio;
+
+ if (!detail) { /* disconnecting after error */
+ hint = tls_error_hint();
+ if (hint != NULL)
+ ERR_add_error_data(2, " : ", hint);
+ }
+ (void)ERR_set_mark();
+ BIO_ssl_shutdown(bio);
+ cbio = BIO_pop(bio); /* connect+HTTP BIO */
+ BIO_free(bio); /* SSL BIO */
+ (void)ERR_pop_to_mark(); /* hide SSL_R_READ_BIO_NOT_SET etc. */
+ bio = cbio;
+ }
+ return bio;
}
void APP_HTTP_TLS_INFO_free(APP_HTTP_TLS_INFO *info)
diff --git a/crypto/http/http_client.c b/crypto/http/http_client.c
index ef0114240b..f786f831bf 100644
--- a/crypto/http/http_client.c
+++ b/crypto/http/http_client.c
@@ -1196,11 +1196,17 @@ BIO *OSSL_HTTP_transfer(OSSL_HTTP_REQ_CTX **prctx,
int OSSL_HTTP_close(OSSL_HTTP_REQ_CTX *rctx, int ok)
{
+ BIO *wbio;
int ret = 1;
- /* callback can be used to clean up TLS session on disconnect */
- if (rctx != NULL && rctx->upd_fn != NULL)
- ret = (*rctx->upd_fn)(rctx->wbio, rctx->upd_arg, 0, ok) != NULL;
+ /* callback can be used to finish TLS session and free its BIO */
+ if (rctx != NULL && rctx->upd_fn != NULL) {
+ wbio = (*rctx->upd_fn)(rctx->wbio, rctx->upd_arg,
+ 0 /* disconnect */, ok);
+ ret = wbio != NULL;
+ if (ret)
+ rctx->wbio = wbio;
+ }
OSSL_HTTP_REQ_CTX_free(rctx);
return ret;
}
diff --git a/doc/man3/OSSL_HTTP_transfer.pod b/doc/man3/OSSL_HTTP_transfer.pod
index 7fcd71dbe0..7e823db3ea 100644
--- a/doc/man3/OSSL_HTTP_transfer.pod
+++ b/doc/man3/OSSL_HTTP_transfer.pod
@@ -113,17 +113,25 @@ or NULL to indicate failure, in which case it should not modify the BIO.
Here is a simple example that supports TLS connections (but not via a proxy):
- BIO *http_tls_cb(BIO *hbio, void *arg, int connect, int detail)
+ BIO *http_tls_cb(BIO *bio, void *arg, int connect, int detail)
{
if (connect && detail) { /* connecting with TLS */
SSL_CTX *ctx = (SSL_CTX *)arg;
BIO *sbio = BIO_new_ssl(ctx, 1);
- hbio = sbio != NULL ? BIO_push(sbio, hbio) : NULL;
- } else if (!connect && !detail) { /* disconnecting after error */
- /* optionally add diagnostics here */
+ bio = sbio != NULL ? BIO_push(sbio, bio) : NULL;
+ } else if (!connect) { /* disconnecting */
+ BIO *hbio;
+
+ if (!detail) { /* an error has occurred */
+ /* optionally add diagnostics here */
+ }
+ BIO_ssl_shutdown(bio);
+ hbio = BIO_pop(bio);
+ BIO_free(bio); /* SSL BIO */
+ bio = hbio;
}
- return hbio;
+ return bio;
}
After disconnect the modified BIO will be deallocated using BIO_free_all().