summaryrefslogtreecommitdiffstats
path: root/crypto/cmp
diff options
context:
space:
mode:
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>2021-04-28 00:26:14 +0200
committerDr. David von Oheimb <dev@ddvo.net>2021-05-14 19:24:42 +0200
commit19f97fe6f10bf0d1daec26a9ae2ad919127c67d5 (patch)
tree4734918abbc423e7c2153b59bb4420fe4022205a /crypto/cmp
parent19a39b29e846e465ee97e7519acf14ddc9302198 (diff)
HTTP: Implement persistent connections (keep-alive)
Both at API and at CLI level (for the CMP app only, so far) there is a new parameter/option: keep_alive. * 0 means HTTP connections are not kept open after receiving a response, which is the default behavior for HTTP 1.0. * 1 means that persistent connections are requested. * 2 means that persistent connections are required, i.e., in case the server does not grant them an error occurs. For the CMP app the default value is 1, which means preferring to keep the connection open. For all other internal uses of the HTTP client (fetching an OCSP response, a cert, or a CRL) it does not matter because these operations just take one round trip. If the client application requested or required a persistent connection and this was granted by the server, it can keep the OSSL_HTTP_REQ_CTX * as long as it wants to send further requests and OSSL_HTTP_is_alive() returns nonzero, else it should call OSSL_HTTP_REQ_CTX_free() or OSSL_HTTP_close(). In case the client application keeps the OSSL_HTTP_REQ_CTX * but the connection then dies for any reason at the server side, it will notice this obtaining an I/O error when trying to send the next request. This requires extending the HTTP header parsing and rearranging the high-level HTTP client API. In particular: * Split the monolithic OSSL_HTTP_transfer() into OSSL_HTTP_open(), OSSL_HTTP_set_request(), a lean OSSL_HTTP_transfer(), and OSSL_HTTP_close(). * Split the timeout functionality accordingly and improve default behavior. * Extract part of OSSL_HTTP_REQ_CTX_new() to OSSL_HTTP_REQ_CTX_set_expected(). * Extend struct ossl_http_req_ctx_st accordingly. Use the new feature for the CMP client, which requires extending related transaction management of CMP client and test server. Update the documentation and extend the tests accordingly. Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/15053)
Diffstat (limited to 'crypto/cmp')
-rw-r--r--crypto/cmp/cmp_ctx.c17
-rw-r--r--crypto/cmp/cmp_http.c38
-rw-r--r--crypto/cmp/cmp_local.h2
3 files changed, 49 insertions, 8 deletions
diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c
index 7e7af63b4a..a09432597b 100644
--- a/crypto/cmp/cmp_ctx.c
+++ b/crypto/cmp/cmp_ctx.c
@@ -115,7 +115,8 @@ OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq)
ctx->status = -1;
ctx->failInfoCode = -1;
- ctx->msg_timeout = 2 * 60;
+ ctx->keep_alive = 1;
+ ctx->msg_timeout = -1;
if ((ctx->untrusted = sk_X509_new_null()) == NULL)
goto oom;
@@ -149,6 +150,11 @@ int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx)
return 0;
}
+ if (ctx->http_ctx != NULL) {
+ (void)OSSL_HTTP_close(ctx->http_ctx, 1);
+ ossl_cmp_debug(ctx, "disconnected from CMP server");
+ ctx->http_ctx = NULL;
+ }
ctx->status = -1;
ctx->failInfoCode = -1;
@@ -169,6 +175,10 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx)
if (ctx == NULL)
return;
+ if (ctx->http_ctx != NULL) {
+ (void)OSSL_HTTP_close(ctx->http_ctx, 1);
+ ossl_cmp_debug(ctx, "disconnected from CMP server");
+ }
OPENSSL_free(ctx->serverPath);
OPENSSL_free(ctx->server);
OPENSSL_free(ctx->proxy);
@@ -1041,6 +1051,9 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val)
case OSSL_CMP_OPT_MAC_ALGNID:
ctx->pbm_mac = val;
break;
+ case OSSL_CMP_OPT_KEEP_ALIVE:
+ ctx->keep_alive = val;
+ break;
case OSSL_CMP_OPT_MSG_TIMEOUT:
ctx->msg_timeout = val;
break;
@@ -1105,6 +1118,8 @@ int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt)
return EVP_MD_type(ctx->pbm_owf);
case OSSL_CMP_OPT_MAC_ALGNID:
return ctx->pbm_mac;
+ case OSSL_CMP_OPT_KEEP_ALIVE:
+ return ctx->keep_alive;
case OSSL_CMP_OPT_MSG_TIMEOUT:
return ctx->msg_timeout;
case OSSL_CMP_OPT_TOTAL_TIMEOUT:
diff --git a/crypto/cmp/cmp_http.c b/crypto/cmp/cmp_http.c
index a358622feb..600955efce 100644
--- a/crypto/cmp/cmp_http.c
+++ b/crypto/cmp/cmp_http.c
@@ -28,6 +28,19 @@
#include <openssl/cmp.h>
#include <openssl/err.h>
+static int keep_alive(int keep_alive, int body_type)
+{
+ if (keep_alive != 0
+ /* Ask for persistent connection only if may need more round trips */
+ && body_type != OSSL_CMP_PKIBODY_IR
+ && body_type != OSSL_CMP_PKIBODY_CR
+ && body_type != OSSL_CMP_PKIBODY_P10CR
+ && body_type != OSSL_CMP_PKIBODY_KUR
+ && body_type != OSSL_CMP_PKIBODY_POLLREQ)
+ keep_alive = 0;
+ return keep_alive;
+}
+
/*
* Send the PKIMessage req and on success return the response, else NULL.
* Any previous error queue entries will likely be removed by ERR_clear_error().
@@ -55,11 +68,12 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
if (ctx->serverPort != 0)
BIO_snprintf(server_port, sizeof(server_port), "%d", ctx->serverPort);
-
tls_used = OSSL_CMP_CTX_get_http_cb_arg(ctx) != NULL;
- ossl_cmp_log2(DEBUG, ctx, "connecting to CMP server %s%s",
- ctx->server, tls_used ? " using TLS" : "");
- rsp = OSSL_HTTP_transfer(NULL, ctx->server, server_port,
+ if (ctx->http_ctx == NULL)
+ ossl_cmp_log3(DEBUG, ctx, "connecting to CMP server %s:%s%s",
+ ctx->server, server_port, tls_used ? " using TLS" : "");
+
+ rsp = OSSL_HTTP_transfer(&ctx->http_ctx, ctx->server, server_port,
ctx->serverPath, tls_used,
ctx->proxy, ctx->no_proxy,
NULL /* bio */, NULL /* rbio */,
@@ -67,12 +81,22 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
0 /* buf_size */, headers,
content_type_pkix, req_mem,
content_type_pkix, 1 /* expect_asn1 */,
- HTTP_DEFAULT_MAX_RESP_LEN,
- ctx->msg_timeout, 0 /* keep_alive */);
+ OSSL_HTTP_DEFAULT_MAX_RESP_LEN,
+ ctx->msg_timeout,
+ keep_alive(ctx->keep_alive, req->body->type));
BIO_free(req_mem);
res = (OSSL_CMP_MSG *)ASN1_item_d2i_bio(it, rsp, NULL);
BIO_free(rsp);
- ossl_cmp_debug(ctx, "disconnected from CMP server");
+
+ if (ctx->http_ctx == NULL)
+ ossl_cmp_debug(ctx, "disconnected from CMP server");
+ /*
+ * Note that on normal successful end of the transaction the connection
+ * is not closed at this level, but this will be done by the CMP client
+ * application via OSSL_CMP_CTX_free() or OSSL_CMP_CTX_reinit().
+ */
+ if (res != NULL)
+ ossl_cmp_debug(ctx, "finished reading response from CMP server");
err:
sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);
return res;
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index b2a3382079..eee609937b 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -40,11 +40,13 @@ struct ossl_cmp_ctx_st {
OSSL_CMP_transfer_cb_t transfer_cb; /* default: OSSL_CMP_MSG_http_perform */
void *transfer_cb_arg; /* allows to store optional argument to cb */
/* HTTP-based transfer */
+ OSSL_HTTP_REQ_CTX *http_ctx;
char *serverPath;
char *server;
int serverPort;
char *proxy;
char *no_proxy;
+ int keep_alive; /* persistent connection: 0=no, 1=prefer, 2=require */
int msg_timeout; /* max seconds to wait for each CMP message round trip */
int total_timeout; /* max number of seconds an enrollment may take, incl. */
/* attempts polling for a response if a 'waiting' PKIStatus is received */