From 4b1fe471ac99b9f8692be85dcbcbf6977eb35c78 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Wed, 25 Mar 2020 13:46:02 +0100 Subject: [PATCH] HTTP client: make server/proxy and port params more consistent; minor other improvements Reviewed-by: Matt Caswell Reviewed-by: David von Oheimb (Merged from https://github.com/openssl/openssl/pull/11404) --- crypto/cmp/cmp_ctx.c | 5 +- crypto/cmp/cmp_http.c | 14 +++--- crypto/cmp/cmp_local.h | 2 +- crypto/err/openssl.txt | 1 + crypto/http/http_client.c | 50 +++++++++++--------- crypto/http/http_err.c | 2 + crypto/http/http_lib.c | 53 +++++++++++++++------ crypto/http/http_local.h | 2 - doc/man3/OSSL_CMP_CTX_new.pod | 41 +++++++++------- doc/man3/OSSL_CMP_MSG_http_perform.pod | 35 +++++++++----- doc/man3/OSSL_HTTP_transfer.pod | 65 ++++++++++++++++---------- include/openssl/cmp.h | 3 +- include/openssl/http.h | 10 ++++ include/openssl/httperr.h | 3 +- test/build.info | 6 ++- test/cmp_ctx_test.c | 11 ++--- util/libcrypto.num | 4 +- util/other.syms | 1 - 18 files changed, 191 insertions(+), 117 deletions(-) diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c index eb799b103c..9a252cca79 100644 --- a/crypto/cmp/cmp_ctx.c +++ b/crypto/cmp/cmp_ctx.c @@ -95,7 +95,6 @@ OSSL_CMP_CTX *OSSL_CMP_CTX_new(void) ctx->status = -1; ctx->failInfoCode = -1; - ctx->serverPort = OSSL_CMP_DEFAULT_PORT; ctx->msg_timeout = 2 * 60; if ((ctx->untrusted_certs = sk_X509_new_null()) == NULL) @@ -146,7 +145,7 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx) return; OPENSSL_free(ctx->serverPath); - OPENSSL_free(ctx->serverName); + OPENSSL_free(ctx->server); OPENSSL_free(ctx->proxy); OPENSSL_free(ctx->no_proxy); @@ -775,7 +774,7 @@ int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx, DEFINE_OSSL_CMP_CTX_set1(proxy, char) /* Set the (HTTP) host name of the CMP server */ -DEFINE_OSSL_CMP_CTX_set1(serverName, char) +DEFINE_OSSL_CMP_CTX_set1(server, char) /* Set the server exclusion list of the HTTP proxy server */ DEFINE_OSSL_CMP_CTX_set1(no_proxy, char) diff --git a/crypto/cmp/cmp_http.c b/crypto/cmp/cmp_http.c index be78d95577..20164944e2 100644 --- a/crypto/cmp/cmp_http.c +++ b/crypto/cmp/cmp_http.c @@ -35,24 +35,24 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req) { - char server_port[32]; + char server_port[32] = { '\0' }; STACK_OF(CONF_VALUE) *headers = NULL; - OSSL_CMP_MSG *res = NULL; const char *const content_type_pkix = "application/pkixcmp"; + OSSL_CMP_MSG *res; - if (ctx == NULL || req == NULL - || ctx->serverName == NULL || ctx->serverPort == 0) { + if (ctx == NULL || req == NULL) { CMPerr(0, CMP_R_NULL_ARGUMENT); - return 0; + return NULL; } if (!X509V3_add_value("Pragma", "no-cache", &headers)) return NULL; - BIO_snprintf(server_port, sizeof(server_port), "%d", ctx->serverPort); + if (ctx->serverPort != 0) + BIO_snprintf(server_port, sizeof(server_port), "%d", ctx->serverPort); res = (OSSL_CMP_MSG *) - OSSL_HTTP_post_asn1(ctx->serverName, server_port, ctx->serverPath, + OSSL_HTTP_post_asn1(ctx->server, server_port, ctx->serverPath, OSSL_CMP_CTX_get_http_cb_arg(ctx) != NULL, ctx->proxy, ctx->no_proxy, NULL, NULL, ctx->http_cb, OSSL_CMP_CTX_get_http_cb_arg(ctx), diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 3017d1910b..c3a080f2bd 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -36,7 +36,7 @@ struct ossl_cmp_ctx_st { void *transfer_cb_arg; /* allows to store optional argument to cb */ /* HTTP-based transfer */ char *serverPath; - char *serverName; + char *server; int serverPort; char *proxy; char *no_proxy; diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 3ee5c31d99..f467ea909f 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2606,6 +2606,7 @@ HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP:112:redirection from https to http HTTP_R_REDIRECTION_NOT_ENABLED:116:redirection not enabled HTTP_R_RESPONSE_LINE_TOO_LONG:113:response line too long HTTP_R_RESPONSE_PARSE_ERROR:104:response parse error +HTTP_R_SOCK_NOT_SUPPORTED:122:sock not supported HTTP_R_STATUS_CODE_UNSUPPORTED:114:status code unsupported HTTP_R_TLS_NOT_ENABLED:107:tls not enabled HTTP_R_TOO_MANY_REDIRECTIONS:115:too many redirections diff --git a/crypto/http/http_client.c b/crypto/http/http_client.c index 0fa1939a02..4c123f81d3 100644 --- a/crypto/http/http_client.c +++ b/crypto/http/http_client.c @@ -21,7 +21,7 @@ #include #include #include "internal/sockets.h" -#include "internal/cryptlib.h" +#include "internal/cryptlib.h" /* for ossl_assert() */ #include "http_local.h" @@ -157,7 +157,7 @@ int OSSL_HTTP_REQ_CTX_header(OSSL_HTTP_REQ_CTX *rctx, const char *server, * Section 5.1.2 of RFC 1945 states that the absoluteURI form is only * allowed when using a proxy */ - if (BIO_printf(rctx->mem, "http://%s", server) <= 0) + if (BIO_printf(rctx->mem, OSSL_HTTP_PREFIX"%s", server) <= 0) return 0; if (port != NULL && BIO_printf(rctx->mem, ":%s", port) <= 0) return 0; @@ -701,10 +701,8 @@ static BIO *HTTP_new_bio(const char *server /* optionally includes ":port" */, const char *port = server_port; BIO *cbio; - if (server == NULL) { - HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER); + if (!ossl_assert(server != NULL)) return NULL; - } if (proxy != NULL) { host = proxy; @@ -714,7 +712,7 @@ static BIO *HTTP_new_bio(const char *server /* optionally includes ":port" */, host_end = strchr(host, '/'); if (host_end != NULL && (size_t)(host_end - host) < sizeof(host_name)) { /* chop trailing string starting with '/' */ - strncpy(host_name, host, host_end - host); + strncpy(host_name, host, host_end - host + 1); host = host_name; } @@ -849,18 +847,28 @@ BIO *OSSL_HTTP_transfer(const char *server, const char *port, const char *path, HTTPerr(0, ERR_R_PASSED_INVALID_ARGUMENT); return NULL; } - /* remaining parameters are checked indirectly by the functions called */ - proxy = http_adapt_proxy(proxy, no_proxy, server, use_ssl); - if (bio != NULL) + if (bio != NULL) { cbio = bio; - else + } else { #ifndef OPENSSL_NO_SOCK + if (server == NULL) { + HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (*port == '\0') + port = NULL; + if (port == NULL && strchr(server, ':') == NULL) + port = use_ssl ? OSSL_HTTPS_PORT : OSSL_HTTP_PORT; + proxy = http_adapt_proxy(proxy, no_proxy, server, use_ssl); if ((cbio = HTTP_new_bio(server, port, proxy)) == NULL) return NULL; #else + HTTPerr(0, HTTP_R_SOCK_NOT_SUPPORTED); return NULL; #endif + } + /* remaining parameters are checked indirectly by the functions called */ (void)ERR_set_mark(); /* prepare removing any spurious libssl errors */ if (rbio == NULL && BIO_connect_retry(cbio, timeout) <= 0) @@ -902,10 +910,10 @@ BIO *OSSL_HTTP_transfer(const char *server, const char *port, const char *path, if (lib == ERR_LIB_SSL || lib == ERR_LIB_HTTP || (lib == ERR_LIB_BIO && reason == BIO_R_CONNECT_TIMEOUT) || (lib == ERR_LIB_BIO && reason == BIO_R_CONNECT_ERROR) -# ifndef OPENSSL_NO_CMP +#ifndef OPENSSL_NO_CMP || (lib == ERR_LIB_CMP && reason == CMP_R_POTENTIALLY_INVALID_CERTIFICATE) -# endif +#endif ) { BIO_snprintf(buf, 200, "server=%s:%s", server, port); ERR_add_error_data(1, buf); @@ -949,8 +957,7 @@ BIO *OSSL_HTTP_transfer(const char *server, const char *port, const char *path, static int redirection_ok(int n_redir, const char *old_url, const char *new_url) { - static const char https[] = "https:"; - int https_len = 6; /* strlen(https) */ + size_t https_len = strlen(OSSL_HTTPS_NAME":"); if (n_redir >= HTTP_VERSION_MAX_REDIRECTIONS) { HTTPerr(0, HTTP_R_TOO_MANY_REDIRECTIONS); @@ -958,8 +965,8 @@ static int redirection_ok(int n_redir, const char *old_url, const char *new_url) } if (*new_url == '/') /* redirection to same server => same protocol */ return 1; - if (strncmp(old_url, https, https_len) == 0 && - strncmp(new_url, https, https_len) != 0) { + if (strncmp(old_url, OSSL_HTTPS_NAME":", https_len) == 0 && + strncmp(new_url, OSSL_HTTPS_NAME":", https_len) != 0) { HTTPerr(0, HTTP_R_REDIRECTION_FROM_HTTPS_TO_HTTP); return 0; } @@ -1122,8 +1129,8 @@ int OSSL_HTTP_proxy_connect(BIO *bio, const char *server, const char *port, const char *proxyuser, const char *proxypass, int timeout, BIO *bio_err, const char *prog) { -# undef BUF_SIZE -# define BUF_SIZE (8 * 1024) +#undef BUF_SIZE +#define BUF_SIZE (8 * 1024) char *mbuf = OPENSSL_malloc(BUF_SIZE); char *mbufp; int read_len = 0; @@ -1132,11 +1139,13 @@ int OSSL_HTTP_proxy_connect(BIO *bio, const char *server, const char *port, int rv; time_t max_time = timeout > 0 ? time(NULL) + timeout : 0; - if (bio == NULL || server == NULL || port == NULL + if (bio == NULL || server == NULL || (bio_err != NULL && prog == NULL)) { HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER); goto end; } + if (port == NULL || *port == '\0') + port = OSSL_HTTPS_PORT; if (mbuf == NULL || fbio == NULL) { BIO_printf(bio_err /* may be NULL */, "%s: out of memory", prog); @@ -1256,6 +1265,5 @@ int OSSL_HTTP_proxy_connect(BIO *bio, const char *server, const char *port, } OPENSSL_free(mbuf); return ret; -# undef BUF_SIZE +#undef BUF_SIZE } - diff --git a/crypto/http/http_err.c b/crypto/http/http_err.c index 0b0699f008..7b6f295170 100644 --- a/crypto/http/http_err.c +++ b/crypto/http/http_err.c @@ -45,6 +45,8 @@ static const ERR_STRING_DATA HTTP_str_reasons[] = { "response line too long"}, {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_RESPONSE_PARSE_ERROR), "response parse error"}, + {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_SOCK_NOT_SUPPORTED), + "sock not supported"}, {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_STATUS_CODE_UNSUPPORTED), "status code unsupported"}, {ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_TLS_NOT_ENABLED), "tls not enabled"}, diff --git a/crypto/http/http_lib.c b/crypto/http/http_lib.c index 41749f00e8..5da5b1e724 100644 --- a/crypto/http/http_lib.c +++ b/crypto/http/http_lib.c @@ -11,6 +11,7 @@ #include #include #include +#include "internal/cryptlib.h" /* for ossl_assert() */ #include "http_local.h" @@ -24,8 +25,11 @@ int OSSL_HTTP_parse_url(const char *url, char **phost, char **pport, { char *p, *buf; char *host; - char *port = "80"; + const char *port = OSSL_HTTP_PORT; + size_t https_len = strlen(OSSL_HTTPS_NAME); + if (!ossl_assert(https_len >= strlen(OSSL_HTTP_NAME))) + return 0; if (url == NULL) { HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER); return 0; @@ -46,16 +50,16 @@ int OSSL_HTTP_parse_url(const char *url, char **phost, char **pport, /* Check for initial colon */ p = strchr(buf, ':'); - if (p == NULL || p - buf > 5 /* strlen("https") */) { + if (p == NULL || (size_t)(p - buf) > https_len) { p = buf; } else { *(p++) = '\0'; - if (strcmp(buf, "https") == 0) { + if (strcmp(buf, OSSL_HTTPS_NAME) == 0) { if (pssl != NULL) *pssl = 1; - port = "443"; - } else if (strcmp(buf, "http") != 0) { + port = OSSL_HTTPS_PORT; + } else if (strcmp(buf, OSSL_HTTP_NAME) != 0) { goto parse_err; } @@ -119,13 +123,21 @@ int OSSL_HTTP_parse_url(const char *url, char **phost, char **pport, int http_use_proxy(const char *no_proxy, const char *server) { - size_t sl = strlen(server); + size_t sl; const char *found = NULL; + if (!ossl_assert(server != NULL)) + return 0; + sl = strlen(server); + + /* + * using environment variable names, both lowercase and uppercase variants, + * compatible with other HTTP client implementations like wget, curl and git + */ if (no_proxy == NULL) no_proxy = getenv("no_proxy"); if (no_proxy == NULL) - no_proxy = getenv("NO_PROXY"); + no_proxy = getenv(OPENSSL_NO_PROXY); if (no_proxy != NULL) found = strstr(no_proxy, server); while (found != NULL @@ -138,17 +150,28 @@ int http_use_proxy(const char *no_proxy, const char *server) const char *http_adapt_proxy(const char *proxy, const char *no_proxy, const char *server, int use_ssl) { - int prefix_len = strlen(HTTP_URL_PREFIX); + const int http_len = strlen(OSSL_HTTP_PREFIX); + const int https_len = strlen(OSSL_HTTPS_PREFIX); + /* + * using environment variable names, both lowercase and uppercase variants, + * compatible with other HTTP client implementations like wget, curl and git + */ if (proxy == NULL) proxy = getenv(use_ssl ? "https_proxy" : "http_proxy"); if (proxy == NULL) - proxy = getenv(use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY"); - if (proxy != NULL && strncmp(proxy, HTTP_URL_PREFIX, prefix_len) == 0) - proxy += prefix_len; /* skip any leading "http://" */ - if (proxy != NULL && *proxy == '\0') - proxy = NULL; - if (proxy != NULL && !http_use_proxy(no_proxy, server)) - proxy = NULL; + proxy = getenv(use_ssl ? OPENSSL_HTTP_PROXY : + OPENSSL_HTTPS_PROXY); + if (proxy == NULL) + return NULL; + + /* skip any leading "http://" or "https://" */ + if (strncmp(proxy, OSSL_HTTP_PREFIX, http_len) == 0) + proxy += http_len; + else if (strncmp(proxy, OSSL_HTTPS_PREFIX, https_len) == 0) + proxy += https_len; + + if (*proxy == '\0' || !http_use_proxy(no_proxy, server)) + return NULL; return proxy; } diff --git a/crypto/http/http_local.h b/crypto/http/http_local.h index dd49dbd854..64b475b818 100644 --- a/crypto/http/http_local.h +++ b/crypto/http/http_local.h @@ -27,8 +27,6 @@ typedef OCSP_REQ_CTX OSSL_HTTP_REQ_CTX; # define OSSL_HTTP_REQ_CTX_get0_mem_bio OCSP_REQ_CTX_get0_mem_bio /* undoc'd */ # define OSSL_HTTP_REQ_CTX_set_max_response_length OCSP_set_max_response_length -# define HTTP_URL_PREFIX "http://" - BIO *HTTP_asn1_item2bio(const ASN1_ITEM *it, ASN1_VALUE *val); OSSL_HTTP_REQ_CTX *HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio, int use_http_proxy, const char *server, const char *port, diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod index 2c1ad59750..d070a59b0b 100644 --- a/doc/man3/OSSL_CMP_CTX_new.pod +++ b/doc/man3/OSSL_CMP_CTX_new.pod @@ -11,11 +11,10 @@ OSSL_CMP_CTX_set_log_cb, OSSL_CMP_CTX_set_log_verbosity, OSSL_CMP_CTX_print_errors, OSSL_CMP_CTX_set1_serverPath, -OSSL_CMP_CTX_set1_serverName, +OSSL_CMP_CTX_set1_server, OSSL_CMP_CTX_set_serverPort, OSSL_CMP_CTX_set1_proxy, OSSL_CMP_CTX_set1_no_proxy, -OSSL_CMP_DEFAULT_PORT, OSSL_CMP_CTX_set_http_cb, OSSL_CMP_CTX_set_http_cb_arg, OSSL_CMP_CTX_get_http_cb_arg, @@ -78,11 +77,10 @@ OSSL_CMP_CTX_set1_senderNonce /* message transfer: */ int OSSL_CMP_CTX_set1_serverPath(OSSL_CMP_CTX *ctx, const char *path); - int OSSL_CMP_CTX_set1_serverName(OSSL_CMP_CTX *ctx, const char *name); + int OSSL_CMP_CTX_set1_server(OSSL_CMP_CTX *ctx, const char *address); int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port); int OSSL_CMP_CTX_set1_proxy(OSSL_CMP_CTX *ctx, const char *name); int OSSL_CMP_CTX_set1_no_proxy(OSSL_CMP_CTX *ctx, const char *names); - #define OSSL_CMP_DEFAULT_PORT 80 int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, HTTP_bio_cb_t cb); int OSSL_CMP_CTX_set_http_cb_arg(OSSL_CMP_CTX *ctx, void *arg); void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx); @@ -306,19 +304,26 @@ It is similar to B but uses the CMP log callback function if set in the C for uniformity with CMP logging if given. Otherwise it uses B to print to STDERR (unless OPENSSL_NO_STDIO is defined). -OSSL_CMP_CTX_set1_serverPath() sets the HTTP path of the CMP server on the host. +OSSL_CMP_CTX_set1_serverPath() sets the HTTP path of the CMP server on the host, +also known as "CMP alias". +The default is "/". -OSSL_CMP_CTX_set1_serverName() sets the given server Address (as IP or name) -in the given OSSL_CMP_CTX structure. +OSSL_CMP_CTX_set1_server() sets the given server B
+(which may be a hostname or IP address or NULL) in the given B. OSSL_CMP_CTX_set_serverPort() sets the port of the CMP server to connect to. -Port defaults to OSSL_CMP_DEFAULT_PORT = 80 if not set explicitly. - -OSSL_CMP_CTX_set1_proxy() sets the HTTP proxy to be used for connecting to the -CMP server. -Defaults to the environment variable B if set, else B -in case no TLS is used, otherwise B if set, else B. -The format is [http://]address[:port][/path] where the optional path is ignored. +If not used or the B argument is 0 +the default port applies, which is 80 for HTTP and 443 for HTTPS. + +OSSL_CMP_CTX_set1_proxy() sets the HTTP proxy to be used for connecting to +the given CMP server unless overruled by any "no_proxy" settings (see below). +If TLS is not used this defaults to the value of +the environment variable B if set, else B. +Otherwise defaults to the value of B if set, else B. +An empty proxy string specifies not to use a proxy. +Else the format is I<[http[s]://]address[:port][/path]>, +where any path given is ignored. +The default port number is 80, or 443 in case "https:" is given. OSSL_CMP_CTX_set1_no_proxy() sets the list of server hostnames not to use an HTTP proxy for. The names may be separated by commas and/or whitespace. @@ -606,7 +611,7 @@ All other functions return 1 on success, 0 on error. The following code does an Initialization Request: cmp_ctx = OSSL_CMP_CTX_new(); - OSSL_CMP_CTX_set1_serverName(cmp_ctx, opt_serverName); + OSSL_CMP_CTX_set1_server(cmp_ctx, address); OSSL_CMP_CTX_set1_referenceValue(cmp_ctx, ref, ref_len); OSSL_CMP_CTX_set1_secretValue(cmp_ctx, sec, sec_len); OSSL_CMP_CTX_set0_newPkey(cmp_ctx, new_pkey, 1); @@ -618,7 +623,7 @@ The following code does an Initialization Request using an external identity certificate (RFC 4210, Appendix E.7): cmp_ctx = OSSL_CMP_CTX_new(); - OSSL_CMP_CTX_set1_serverName(cmp_ctx, sname); + OSSL_CMP_CTX_set1_server(cmp_ctx, sname); OSSL_CMP_CTX_set1_clCert(cmp_ctx, cl_cert); OSSL_CMP_CTX_set1_pkey(cmp_ctx, pkey); OSSL_CMP_CTX_set0_newPkey(cmp_ctx, new_pkey, 1); @@ -633,7 +638,7 @@ which is trusted by the current CA the code will connect to. The following code does a Key Update Request: cmp_ctx = OSSL_CMP_CTX_new(); - OSSL_CMP_CTX_set1_serverName(cmp_ctx, sname); + OSSL_CMP_CTX_set1_server(cmp_ctx, url); OSSL_CMP_CTX_set1_pkey(cmp_ctx, pkey); OSSL_CMP_CTX_set0_newPkey(cmp_ctx, new_pkey, 1); OSSL_CMP_CTX_set1_clCert(cmp_ctx, cl_cert); @@ -646,7 +651,7 @@ including, as an example, the id-it-signKeyPairTypes OID and prints info on the General Response contents. cmp_ctx = OSSL_CMP_CTX_new(); - OSSL_CMP_CTX_set1_serverName(cmp_ctx, sname); + OSSL_CMP_CTX_set1_server(cmp_ctx, sname); OSSL_CMP_CTX_set1_referenceValue(cmp_ctx, ref, ref_len); OSSL_CMP_CTX_set1_secretValue(cmp_ctx, sec, sec_len); diff --git a/doc/man3/OSSL_CMP_MSG_http_perform.pod b/doc/man3/OSSL_CMP_MSG_http_perform.pod index 92f6000867..6582d4413b 100644 --- a/doc/man3/OSSL_CMP_MSG_http_perform.pod +++ b/doc/man3/OSSL_CMP_MSG_http_perform.pod @@ -3,35 +3,46 @@ =head1 NAME OSSL_CMP_MSG_http_perform -- implementation of HTTP transfer for CMP messages +- client-side HTTP(S) transfer of a CMP request-response pair =head1 SYNOPSIS #include - SSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx, - const OSSL_CMP_MSG *req); + OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx, + const OSSL_CMP_MSG *req); =head1 DESCRIPTION -This is the API for creating a BIO for CMP (Certificate Management -Protocol) over HTTP(S) with OpenSSL. - -OSSL_CMP_MSG_http_perform() sends the given PKIMessage req to the CMP server -specified in ctx. On success it returns the server's response. +OSSL_CMP_MSG_http_perform() sends the given PKIMessage B +to the CMP server specified in B via L +and optionally L, using +any "CMP alias" optionally specified via L. +The default port is 80 for HTTP and 443 for HTTPS; the default path is "/". +On success the function returns the server's response PKIMessage. + +The function makes use of any HTTP callback function +set via L. +It respects any timeout value set via L +with an B argument. +It also respects any HTTP(S) proxy options set via L +and L and the respective environment variables. +Proxying plain HTTP is supported directly, +while using a proxy for HTTPS connections requires a suitable callback function +such as L. =head1 NOTES -CMP is defined in RFC 4210 (and CRMF in RFC 4211). +CMP is defined in RFC 4210. +HTTP transfer for CMP is defined in RFC 6712. =head1 RETURN VALUES -OSSL_CMP_MSG_http_perform() returns a message on success or else NULL. -It uses ctx->http_cb if set and respects ctx->msgTimeOut. +OSSL_CMP_MSG_http_perform() returns a CMP message on success, else NULL. =head1 SEE ALSO -L, L +L, L. =head1 HISTORY diff --git a/doc/man3/OSSL_HTTP_transfer.pod b/doc/man3/OSSL_HTTP_transfer.pod index 27f438114e..632f48dbe8 100644 --- a/doc/man3/OSSL_HTTP_transfer.pod +++ b/doc/man3/OSSL_HTTP_transfer.pod @@ -69,17 +69,18 @@ and returns it on success as a pointer to I. OSSL_HTTP_post_asn1() uses the HTTP POST method to send a request B with the ASN.1 structure defined in B and the given B to -the given B and optional B and B, which defaults to "/". +the given B and optional B and B. If B is nonzero a TLS connection is requested and the B parameter, described below, must be provided. The optional list B may contain additional custom HTTP header lines. The expected structure of the response is specified by B. On success it returns the response as a pointer to B. -OSSL_HTTP_transfer() exchanges an HTTP request and response with -the given B and optional B and B, which defaults to "/". -If B is nonzero a TLS connection is requested and the B -parameter, described below, must be provided. +OSSL_HTTP_transfer() exchanges any form of HTTP request and response. +It implements the core of the functions described above. +If B parameter is NULL it defaults to "/". +If B is nonzero a TLS connection is requested +and the B parameter, described below, must be provided. If B is NULL it uses the HTTP GET method, else it uses HTTP POST to send a request with the contents of the memory BIO and optional B. The optional list B may contain additional custom HTTP header lines. @@ -91,30 +92,36 @@ L. The above functions have the following parameters in common. -If the optional B parameter contains a non-empty string or -it is NULL and one of the environment variables B and B -(or B and B, respectively, in case B != 0) -is set and contains a non-empty string this is used as the candidate address -of HTTP(S) proxy to use. -The address may include a port specification separated by ':'. -Any prefix "http://" and any trailing string starting with '/' is ignored. -The HTTP client functions connect via the given proxy unless the B -is found in the optional list B of proxy hostnames (if it is not NULL, -else in the environment variable B if set or else in B). -Proxying plain HTTP is supported directly, -while using a proxy for HTTPS connections requires a suitable callback function -such as OSSL_HTTP_proxy_connect(), described below. - -Typically the B and B parameters are NULL and the client creates a -network BIO internally for connecting to the given server and port (optionally -via a proxy and its port), and uses it for exchanging the request and response. -If B is given and B is NULL then the client uses this BIO instead. +Typically the OpenSSL build supports sockets +and the B and B parameters are both NULL. +In this case the client creates a network BIO internally +for connecting to the given B +at the specified B (if any, defaulting to 80 for HTTP or 443 for HTTPS), +optionally via a B (respecting B) as described below. +Then the client uses this internal BIO for exchanging the request and response. +If B is given and B is NULL then the client uses this B instead. If both B and B are given (which may be memory BIOs for instance) then no explicit connection is attempted, B is used for writing the request, and B for reading the response. As soon as the client has flushed B the server must be ready to provide a response or indicate a waiting condition via B. +The optional B parameter can be used to set the address of the an +HTTP(S) proxy to use (unless overridden by "no_proxy" settings). +If TLS is not used this defaults to the environment variable B +if set, else B. +If B != 0 it defaults to B if set, else B. +An empty proxy string specifies not to use a proxy. +Else the format is I<[http[s]://]address[:port][/path]>, +where any path given is ignored. +The default proxy port number is 80, or 443 in case "https:" is given. +The HTTP client functions connect via the given proxy unless the B +is found in the optional list B of proxy hostnames (if not NULL; +default is the environment variable B if set, else B). +Proxying plain HTTP is supported directly, +while using a proxy for HTTPS connections requires a suitable callback function +such as B, described below. + The B parameter specifies the response header maximum line length, where 0 indicates the default value, which currently is 4k. The B parameter specifies the maximum response length, @@ -123,7 +130,7 @@ where 0 indicates the default value, which currently is 100k. An ASN.1-encoded response is expected by OSSL_HTTP_get_asn1() and OSSL_HTTP_post_asn1(), while for OSSL_HTTP_get() or OSSL_HTTP_transfer() this is only the case if the B parameter is nonzero. -If the response header contains one or more Content-Length header lines and/or +If the response header contains one or more "Content-Length" header lines and/or an ASN.1-encoded response is expected, which should include a total length, the length indications received are checked for consistency and for not exceeding the maximum response length. @@ -172,11 +179,12 @@ Here is a simple example that supports TLS connections (but not via a proxy): After disconnect the modified BIO will be deallocated using BIO_free_all(). OSSL_HTTP_proxy_connect() may be used by an above BIO connect callback function -to set up an SSL/TLS connection via an HTTP proxy. +to set up an SSL/TLS connection via an HTTPS proxy. It promotes the given BIO B representing a connection pre-established with a TLS proxy using the HTTP CONNECT method, optionally using proxy client credentials B and B, to connect with TLS protection ultimately to B and B. +If the B argument is NULL or the empty string it defaults to "443". The B parameter is used as described above. Since this function is typically called by appplications such as L it uses the B and B parameters (unless @@ -192,6 +200,13 @@ them copies of the respective string components. The strings returned this way must be deallocated by the caller using L unless they are NULL, which is their default value on error. +=head1 NOTES + +The names of the environment variables used by this implementation: +B, B, B, B, B, and +B, have been chosen for maximal compatibility with +other HTTP client implementations such as wget, curl, and git. + =head1 RETURN VALUES OSSL_HTTP_get(), OSSL_HTTP_get_asn1(), OSSL_HTTP_post_asn1(), and diff --git a/include/openssl/cmp.h b/include/openssl/cmp.h index 536f26b3c8..b594296565 100644 --- a/include/openssl/cmp.h +++ b/include/openssl/cmp.h @@ -274,9 +274,8 @@ int OSSL_CMP_CTX_set_log_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_log_cb_t cb); void OSSL_CMP_CTX_print_errors(OSSL_CMP_CTX *ctx); /* message transfer: */ int OSSL_CMP_CTX_set1_serverPath(OSSL_CMP_CTX *ctx, const char *path); -int OSSL_CMP_CTX_set1_serverName(OSSL_CMP_CTX *ctx, const char *name); +int OSSL_CMP_CTX_set1_server(OSSL_CMP_CTX *ctx, const char *address); int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port); -# define OSSL_CMP_DEFAULT_PORT 80 int OSSL_CMP_CTX_set1_proxy(OSSL_CMP_CTX *ctx, const char *name); int OSSL_CMP_CTX_set1_no_proxy(OSSL_CMP_CTX *ctx, const char *names); int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, OSSL_HTTP_bio_cb_t cb); diff --git a/include/openssl/http.h b/include/openssl/http.h index d618e5905b..4dff008801 100644 --- a/include/openssl/http.h +++ b/include/openssl/http.h @@ -25,6 +25,16 @@ extern "C" { typedef BIO *(*OSSL_HTTP_bio_cb_t)(BIO *bio, void *arg, int connect, int detail); +# define OSSL_HTTP_NAME "http" +# define OSSL_HTTPS_NAME "https" +# define OSSL_HTTP_PREFIX OSSL_HTTP_NAME"://" +# define OSSL_HTTPS_PREFIX OSSL_HTTPS_NAME"://" +# define OSSL_HTTP_PORT "80" +# define OSSL_HTTPS_PORT "443" +# define OPENSSL_NO_PROXY "NO_PROXY" +# define OPENSSL_HTTP_PROXY "HTTP_PROXY" +# define OPENSSL_HTTPS_PROXY "HTTPS_PROXY" + BIO *OSSL_HTTP_get(const char *url, const char *proxy, const char *no_proxy, BIO *bio, BIO *rbio, OSSL_HTTP_bio_cb_t bio_update_fn, void *arg, diff --git a/include/openssl/httperr.h b/include/openssl/httperr.h index cda4a34332..e4acb1df8c 100644 --- a/include/openssl/httperr.h +++ b/include/openssl/httperr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -47,6 +47,7 @@ int ERR_load_HTTP_strings(void); # define HTTP_R_REDIRECTION_NOT_ENABLED 116 # define HTTP_R_RESPONSE_LINE_TOO_LONG 113 # define HTTP_R_RESPONSE_PARSE_ERROR 104 +# define HTTP_R_SOCK_NOT_SUPPORTED 122 # define HTTP_R_STATUS_CODE_UNSUPPORTED 114 # define HTTP_R_TLS_NOT_ENABLED 107 # define HTTP_R_TOO_MANY_REDIRECTIONS 115 diff --git a/test/build.info b/test/build.info index b6c3a6e4bb..6d670ea175 100644 --- a/test/build.info +++ b/test/build.info @@ -51,7 +51,7 @@ IF[{- !$disabled{tests} -}] x509_time_test x509_dup_cert_test x509_check_cert_pkey_test \ recordlentest drbgtest drbg_cavs_test drbg_extra_test sslbuffertest \ time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \ - servername_test ocspapitest fatalerrtest tls13ccstest \ + http_test servername_test ocspapitest fatalerrtest tls13ccstest \ sysdefaulttest errtest ssl_ctx_test gosttest \ context_internal_test aesgcmtest params_test evp_pkey_dparams_test \ keymgmt_internal_test @@ -380,6 +380,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[ciphername_test]=../include ../apps/include DEPEND[ciphername_test]=../libcrypto ../libssl libtestutil.a + SOURCE[http_test]=http_test.c + INCLUDE[http_test]=../include ../apps/include + DEPEND[http_test]=../libcrypto libtestutil.a + SOURCE[servername_test]=servername_test.c ssltestlib.c INCLUDE[servername_test]=../include ../apps/include DEPEND[servername_test]=../libcrypto ../libssl libtestutil.a diff --git a/test/cmp_ctx_test.c b/test/cmp_ctx_test.c index 1708960687..e6b42db11b 100644 --- a/test/cmp_ctx_test.c +++ b/test/cmp_ctx_test.c @@ -492,7 +492,6 @@ static X509_STORE *X509_STORE_new_1(void) #define IS_NEG(x) ((x) < 0) #define IS_0(x) ((x) == 0) /* for any type */ -#define IS_DEFAULT_PORT(x) ((x) == OSSL_CMP_DEFAULT_PORT) #define DROP(x) (void)(x) /* dummy free() for non-pointer and function types */ #define ERR(x) (CMPerr(0, CMP_R_NULL_ARGUMENT), x) @@ -555,12 +554,12 @@ typedef OSSL_HTTP_bio_cb_t OSSL_CMP_http_cb_t; DEFAULT, 1, DROP) #define DEFINE_SET_GET_INT_TEST(OSSL_CMP, CTX, FIELD) \ DEFINE_SET_GET_INT_TEST_DEFAULT(OSSL_CMP, CTX, FIELD, IS_NEG) -#define DEFINE_SET_PORT_TEST(FIELD) \ +#define DEFINE_SET_INT_TEST(FIELD) \ static int OSSL_CMP_CTX_get_##FIELD(const CMP_CTX *ctx) \ { \ return ctx == NULL ? ERR(-1) : ctx->FIELD; \ } \ - DEFINE_SET_GET_INT_TEST_DEFAULT(OSSL_CMP, CTX, FIELD, IS_DEFAULT_PORT) + DEFINE_SET_GET_INT_TEST_DEFAULT(OSSL_CMP, CTX, FIELD, IS_0) #define DEFINE_SET_GET_ARG_FN(SETN, GETN, FIELD, ARG, T) \ static int OSSL_CMP_CTX_##SETN##_##FIELD##_##ARG(CMP_CTX *ctx, T val) \ @@ -716,8 +715,8 @@ DEFINE_SET_GET_BASE_TEST(OSSL_CMP_CTX, set, get, 0, option_16, int, -1, IS_0, \ DEFINE_SET_CB_TEST(log_cb) DEFINE_SET_TEST_DEFAULT(OSSL_CMP, CTX, 1, 1, serverPath, char, IS_0) -DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, serverName, char) -DEFINE_SET_PORT_TEST(serverPort) +DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, server, char) +DEFINE_SET_INT_TEST(serverPort) DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, proxy, char) DEFINE_SET_TEST(OSSL_CMP, CTX, 1, 1, no_proxy, char) DEFINE_SET_CB_TEST(http_cb) @@ -801,7 +800,7 @@ int setup_tests(void) #endif /* message transfer: */ ADD_TEST(test_CTX_set1_get0_serverPath); - ADD_TEST(test_CTX_set1_get0_serverName); + ADD_TEST(test_CTX_set1_get0_server); ADD_TEST(test_CTX_set_get_serverPort); ADD_TEST(test_CTX_set1_get0_proxy); ADD_TEST(test_CTX_set1_get0_no_proxy); diff --git a/util/libcrypto.num b/util/libcrypto.num index ced0921148..12761e4adc 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4755,7 +4755,7 @@ OSSL_CMP_CTX_get_option ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_set_log_cb ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_print_errors ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_set1_serverPath ? 3_0_0 EXIST::FUNCTION:CMP -OSSL_CMP_CTX_set1_serverName ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_CTX_set1_server ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_set_serverPort ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_set1_proxy ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_CTX_set1_no_proxy ? 3_0_0 EXIST::FUNCTION:CMP @@ -4990,9 +4990,9 @@ OSSL_CMP_exec_CR_ses ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_exec_P10CR_ses ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_exec_KUR_ses ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_try_certreq ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_certConf_cb ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_exec_RR_ses ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_exec_GENM_ses ? 3_0_0 EXIST::FUNCTION:CMP -OSSL_CMP_certConf_cb ? 3_0_0 EXIST::FUNCTION:CMP OSSL_CMP_MSG_http_perform ? 3_0_0 EXIST::FUNCTION:CMP EVP_PKEY_gen ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_set_rsa_keygen_bits ? 3_0_0 EXIST::FUNCTION:RSA diff --git a/util/other.syms b/util/other.syms index 508653f86b..90fba73ca9 100644 --- a/util/other.syms +++ b/util/other.syms @@ -353,7 +353,6 @@ OpenSSL_add_all_digests define deprecated 1.1.0 OpenSSL_add_ssl_algorithms define OSSL_CMP_CTX_set_log_verbosity define OSSL_CMP_CR define -OSSL_CMP_DEFAULT_PORT define OSSL_CMP_IR define OSSL_CMP_KUR define OSSL_CMP_LOG_ALERT define -- 2.25.1