HTTP client: Minimal changes that include the improved API

This is a minimal version of pull request #15053 including all the
proposed improvements to the HTTP client API and its documentation
but only those code adaptations strictly needed for it.

The proposed new features include
* support for persistent connections (keep-alive),
* generalization to arbitrary request and response types, and
* support for streaming BIOs for request and response data.

The related API changes include:
* 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().

Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15147)
This commit is contained in:
Dr. David von Oheimb 2021-05-05 00:09:43 +02:00 committed by Dr. David von Oheimb
parent 4329f361ce
commit 8f965908a5
23 changed files with 604 additions and 492 deletions

View File

@ -358,18 +358,20 @@ OpenSSL 3.0
* Deprecated the type OCSP_REQ_CTX and the functions OCSP_REQ_CTX_new(),
OCSP_REQ_CTX_free(), OCSP_REQ_CTX_http(), OCSP_REQ_CTX_add1_header(),
OCSP_REQ_CTX_i2d() and its special form OCSP_REQ_CTX_set1_req(),
OCSP_REQ_CTX_nbio(), OCSP_REQ_CTX_nbio_d2i(),
OCSP_REQ_CTX_nbio(),
OCSP_REQ_CTX_nbio_d2i() and its special form OCSP_sendreq_nbio(),
OCSP_REQ_CTX_get0_mem_bio() and OCSP_set_max_response_length(). These
were used to collect all necessary data to form a HTTP request, and to
perform the HTTP transfer with that request. With OpenSSL 3.0, the
type is OSSL_HTTP_REQ_CTX, and the deprecated functions are replaced
with OSSL_HTTP_REQ_CTX_new(), OSSL_HTTP_REQ_CTX_free(),
OSSL_HTTP_REQ_CTX_set_request_line(), OSSL_HTTP_REQ_CTX_add1_header(),
OSSL_HTTP_REQ_CTX_i2d(), OSSL_HTTP_REQ_CTX_nbio(),
OSSL_HTTP_REQ_CTX_sendreq_d2i(), OSSL_HTTP_REQ_CTX_get0_mem_bio() and
OSSL_HTTP_REQ_CTX_set1_req(),
OSSL_HTTP_REQ_CTX_nbio(), OSSL_HTTP_REQ_CTX_nbio_d2i(),
OSSL_HTTP_REQ_CTX_get0_mem_bio(), and
OSSL_HTTP_REQ_CTX_set_max_response_length().
*Rich Salz and Richard Levitte*
*Rich Salz, Richard Levitte, and David von Oheimb*
* Deprecated `X509_http_nbio()` and `X509_CRL_http_nbio()`,
which are superseded by `X509_load_http()` and `X509_CRL_load_http()`.
@ -812,8 +814,12 @@ OpenSSL 3.0
*David von Oheimb, Martin Peylo*
* Generalized the HTTP client code from `crypto/ocsp/` into `crpyto/http/`.
The legacy OCSP-focused and only partly documented API is retained for
backward compatibility. See L<OSSL_CMP_MSG_http_perform(3)> etc. for details.
It supports arbitrary request and response content types, GET redirection,
TLS, connections via HTTP(S) proxies, connections and exchange via
user-defined BIOs (allowing implicit connections), persistent connections,
and timeout checks. See L<OSSL_HTTP_transfer(3)> etc. for details.
The legacy OCSP-focused (and only partly documented) API
is retained for backward compatibility, while most of it is deprecated.
*David von Oheimb*

View File

@ -2479,6 +2479,7 @@ ASN1_VALUE *app_http_get_asn1(const char *url, const char *proxy,
char *server;
char *port;
int use_ssl;
BIO *mem;
ASN1_VALUE *resp = NULL;
if (url == NULL || it == NULL) {
@ -2500,10 +2501,13 @@ ASN1_VALUE *app_http_get_asn1(const char *url, const char *proxy,
info.use_proxy = proxy != NULL;
info.timeout = timeout;
info.ssl_ctx = ssl_ctx;
resp = OSSL_HTTP_get_asn1(url, proxy, no_proxy,
NULL, NULL, app_http_tls_cb, &info,
headers, 0 /* maxline */, 0 /* max_resp_len */,
timeout, expected_content_type, it);
mem = OSSL_HTTP_get(url, proxy, no_proxy, NULL /* bio */, NULL /* rbio */,
app_http_tls_cb, &info, 0 /* buf_size */, headers,
expected_content_type, 1 /* expect_asn1 */,
HTTP_DEFAULT_MAX_RESP_LEN, timeout);
resp = ASN1_item_d2i_bio(it, mem, NULL);
BIO_free(mem);
end:
OPENSSL_free(server);
OPENSSL_free(port);
@ -2520,18 +2524,27 @@ ASN1_VALUE *app_http_post_asn1(const char *host, const char *port,
long timeout, const ASN1_ITEM *rsp_it)
{
APP_HTTP_TLS_INFO info;
BIO *rsp, *req_mem = ASN1_item_i2d_mem_bio(req_it, req);
ASN1_VALUE *res;
if (req_mem == NULL)
return NULL;
info.server = host;
info.port = port;
info.use_proxy = proxy != NULL;
info.timeout = timeout;
info.ssl_ctx = ssl_ctx;
return OSSL_HTTP_post_asn1(host, port, path, ssl_ctx != NULL,
proxy, no_proxy,
NULL, NULL, app_http_tls_cb, &info,
headers, content_type, req, req_it,
0 /* maxline */,
0 /* max_resp_len */, timeout, NULL, rsp_it);
rsp = OSSL_HTTP_transfer(NULL, host, port, path, ssl_ctx != NULL,
proxy, no_proxy, NULL /* bio */, NULL /* rbio */,
app_http_tls_cb, &info,
0 /* buf_size */, headers, content_type, req_mem,
NULL /* expected_ct */, 1 /* expect_asn1 */,
HTTP_DEFAULT_MAX_RESP_LEN, timeout,
0 /* keep_alive */);
BIO_free(req_mem);
res = ASN1_item_d2i_bio(rsp_it, rsp, NULL);
BIO_free(rsp);
return res;
}
#endif

View File

@ -37,9 +37,11 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
{
char server_port[32] = { '\0' };
STACK_OF(CONF_VALUE) *headers = NULL;
const char *const content_type_pkix = "application/pkixcmp";
const char content_type_pkix[] = "application/pkixcmp";
int tls_used;
OSSL_CMP_MSG *res;
const ASN1_ITEM *it = ASN1_ITEM_rptr(OSSL_CMP_MSG);
BIO *req_mem, *rsp;
OSSL_CMP_MSG *res = NULL;
if (ctx == NULL || req == NULL) {
ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
@ -48,6 +50,8 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
if (!X509V3_add_value("Pragma", "no-cache", &headers))
return NULL;
if ((req_mem = ASN1_item_i2d_mem_bio(it, (const ASN1_VALUE *)req)) == NULL)
goto err;
if (ctx->serverPort != 0)
BIO_snprintf(server_port, sizeof(server_port), "%d", ctx->serverPort);
@ -55,15 +59,21 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
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" : "");
res = (OSSL_CMP_MSG *)
OSSL_HTTP_post_asn1(ctx->server, server_port, ctx->serverPath,
tls_used, ctx->proxy, ctx->no_proxy, NULL, NULL,
ctx->http_cb, OSSL_CMP_CTX_get_http_cb_arg(ctx),
headers, content_type_pkix, (const ASN1_VALUE *)req,
ASN1_ITEM_rptr(OSSL_CMP_MSG),
0, 0, ctx->msg_timeout, content_type_pkix,
ASN1_ITEM_rptr(OSSL_CMP_MSG));
rsp = OSSL_HTTP_transfer(NULL, ctx->server, server_port,
ctx->serverPath, tls_used,
ctx->proxy, ctx->no_proxy,
NULL /* bio */, NULL /* rbio */,
ctx->http_cb, OSSL_CMP_CTX_get_http_cb_arg(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 */);
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");
err:
sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);
return res;
}

View File

@ -48,12 +48,14 @@ struct ossl_http_req_ctx_st {
BIO *rbio; /* BIO to read response from */
BIO *mem; /* Memory BIO response is built into */
int method_POST; /* HTTP method is "POST" (else "GET") */
const char *expected_ct; /* expected Content-Type, or NULL */
char *expected_ct; /* expected Content-Type, or NULL */
int expect_asn1; /* response must be ASN.1-encoded */
long len_to_send; /* number of bytes in request still to send */
unsigned long resp_len; /* length of response */
unsigned long max_resp_len; /* Maximum length of response */
time_t max_time; /* Maximum end time of the transfer, or 0 */
int keep_alive; /* Persistent conn. 0=no, 1=prefer, 2=require */
time_t max_time; /* Maximum end time of current transfer, or 0 */
time_t max_total_time; /* Maximum end time of total transfer, or 0 */
char *redirection_url; /* Location given with HTTP status 301/302 */
};
@ -72,10 +74,7 @@ struct ossl_http_req_ctx_st {
#define OHS_DONE (8 | OHS_NOREAD) /* Completed */
#define OHS_HTTP_HEADER (9 | OHS_NOREAD) /* Headers set, w/o final \r\n */
OSSL_HTTP_REQ_CTX *OSSL_HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
int expect_asn1)
OSSL_HTTP_REQ_CTX *OSSL_HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio, int maxline)
{
OSSL_HTTP_REQ_CTX *rctx;
@ -95,11 +94,8 @@ OSSL_HTTP_REQ_CTX *OSSL_HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio,
OPENSSL_free(rctx);
return NULL;
}
rctx->expected_ct = expected_ct;
rctx->expect_asn1 = expect_asn1;
rctx->resp_len = 0;
OSSL_HTTP_REQ_CTX_set_max_response_length(rctx, max_resp_len);
rctx->max_time = timeout > 0 ? time(NULL) + timeout : 0;
rctx->max_resp_len = HTTP_DEFAULT_MAX_RESP_LEN;
/* everything else is 0, e.g. rctx->len_to_send, or NULL, e.g. rctx->mem */
return rctx;
}
@ -110,6 +106,7 @@ void OSSL_HTTP_REQ_CTX_free(OSSL_HTTP_REQ_CTX *rctx)
return;
BIO_free(rctx->mem); /* this may indirectly call ERR_clear_error() */
OPENSSL_free(rctx->readbuf);
OPENSSL_free(rctx->expected_ct);
OPENSSL_free(rctx);
}
@ -122,6 +119,15 @@ BIO *OSSL_HTTP_REQ_CTX_get0_mem_bio(const OSSL_HTTP_REQ_CTX *rctx)
return rctx->mem;
}
size_t OSSL_HTTP_REQ_CTX_get_resp_len(const OSSL_HTTP_REQ_CTX *rctx)
{
if (rctx == NULL) {
ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
return rctx->resp_len;
}
void OSSL_HTTP_REQ_CTX_set_max_response_length(OSSL_HTTP_REQ_CTX *rctx,
unsigned long len)
{
@ -201,6 +207,36 @@ int OSSL_HTTP_REQ_CTX_add1_header(OSSL_HTTP_REQ_CTX *rctx,
return 1;
}
int OSSL_HTTP_REQ_CTX_set_expected(OSSL_HTTP_REQ_CTX *rctx,
const char *content_type, int asn1,
int timeout, int keep_alive)
{
if (rctx == NULL) {
ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
return 0;
}
if (keep_alive != 0
&& rctx->state != OHS_ERROR && rctx->state != OHS_HEADERS) {
/* Cannot anymore set keep-alive in request header */
ERR_raise(ERR_LIB_HTTP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
OPENSSL_free(rctx->expected_ct);
rctx->expected_ct = NULL;
if (content_type != NULL
&& (rctx->expected_ct = OPENSSL_strdup(content_type)) == NULL)
return 0;
rctx->expect_asn1 = asn1;
if (timeout >= 0)
rctx->max_time = timeout > 0 ? time(NULL) + timeout : 0;
else
rctx->max_time = rctx->max_total_time;
rctx->keep_alive = keep_alive;
return 1;
}
static int ossl_http_req_ctx_set_content(OSSL_HTTP_REQ_CTX *rctx,
const char *content_type, BIO *req_mem)
{
@ -228,26 +264,8 @@ static int ossl_http_req_ctx_set_content(OSSL_HTTP_REQ_CTX *rctx,
&& BIO_write(rctx->mem, req, req_len) == (int)req_len;
}
BIO *ossl_http_asn1_item2bio(const ASN1_ITEM *it, const ASN1_VALUE *val)
{
BIO *res;
if (it == NULL || val == NULL) {
ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
if ((res = BIO_new(BIO_s_mem())) == NULL)
return NULL;
if (ASN1_item_i2d_bio(it, res, val) <= 0) {
BIO_free(res);
res = NULL;
}
return res;
}
int OSSL_HTTP_REQ_CTX_set1_req(OSSL_HTTP_REQ_CTX *rctx, const char *content_type,
const ASN1_ITEM *it, ASN1_VALUE *req)
const ASN1_ITEM *it, const ASN1_VALUE *req)
{
BIO *mem;
int res;
@ -257,7 +275,7 @@ int OSSL_HTTP_REQ_CTX_set1_req(OSSL_HTTP_REQ_CTX *rctx, const char *content_type
return 0;
}
res = (mem = ossl_http_asn1_item2bio(it, req)) != NULL
res = (mem = ASN1_item_i2d_mem_bio(it, req)) != NULL
&& ossl_http_req_ctx_set_content(rctx, content_type, mem);
BIO_free(mem);
return res;
@ -289,14 +307,13 @@ static int OSSL_HTTP_REQ_CTX_add1_headers(OSSL_HTTP_REQ_CTX *rctx,
* If !use_http_proxy then the 'server' and 'port' parameters are ignored.
* If req_mem == NULL then use GET and ignore content_type, else POST.
*/
OSSL_HTTP_REQ_CTX
static OSSL_HTTP_REQ_CTX
*ossl_http_req_ctx_new(BIO *wbio, BIO *rbio, int use_http_proxy,
const char *server, const char *port,
const char *path,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req_mem,
int maxline, unsigned long max_resp_len,
int timeout,
int maxline, int timeout,
const char *expected_ct, int expect_asn1)
{
OSSL_HTTP_REQ_CTX *rctx;
@ -307,14 +324,14 @@ OSSL_HTTP_REQ_CTX
}
/* remaining parameters are checked indirectly by the functions called */
if ((rctx = OSSL_HTTP_REQ_CTX_new(wbio, rbio, maxline, max_resp_len, timeout,
expected_ct, expect_asn1))
if ((rctx = OSSL_HTTP_REQ_CTX_new(wbio, rbio, maxline))
== NULL)
return NULL;
if (OSSL_HTTP_REQ_CTX_set_request_line(rctx, req_mem != NULL,
use_http_proxy ? server : NULL, port,
path)
&& OSSL_HTTP_REQ_CTX_set_expected(rctx, expected_ct, expect_asn1,
timeout, 0)
&& OSSL_HTTP_REQ_CTX_add1_headers(rctx, headers, server)
&& (req_mem == NULL
|| ossl_http_req_ctx_set_content(rctx, content_type, req_mem)))
@ -588,6 +605,7 @@ int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
rctx->expected_ct, value);
return 0;
}
OPENSSL_free(rctx->expected_ct);
rctx->expected_ct = NULL; /* content-type has been found */
}
if (strcasecmp(key, "Content-Length") == 0) {
@ -688,6 +706,20 @@ int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
}
}
int OSSL_HTTP_REQ_CTX_nbio_d2i(OSSL_HTTP_REQ_CTX *rctx,
ASN1_VALUE **pval, const ASN1_ITEM *it)
{
const unsigned char *p;
int rv;
*pval = NULL;
if ((rv = OSSL_HTTP_REQ_CTX_nbio(rctx)) != 1)
return rv;
*pval = ASN1_item_d2i(NULL, &p, BIO_get_mem_data(rctx->mem, &p), it);
return *pval != NULL;
}
#ifndef OPENSSL_NO_SOCK
/* set up a new connection BIO, to HTTP server or to HTTP(S) proxy if given */
@ -723,20 +755,12 @@ static BIO *HTTP_new_bio(const char *server /* optionally includes ":port" */,
}
#endif /* OPENSSL_NO_SOCK */
static ASN1_VALUE *BIO_mem_d2i(BIO *mem, const ASN1_ITEM *it)
int OSSL_HTTP_is_alive(const OSSL_HTTP_REQ_CTX *rctx)
{
const unsigned char *p;
ASN1_VALUE *resp;
if (mem == NULL)
return NULL;
if ((resp = ASN1_item_d2i(NULL, &p, BIO_get_mem_data(mem, &p), it)) == NULL)
ERR_raise(ERR_LIB_HTTP, HTTP_R_RESPONSE_PARSE_ERROR);
return resp;
return rctx != NULL && rctx->keep_alive != 0;
}
static BIO *ossl_http_req_ctx_transfer(OSSL_HTTP_REQ_CTX *rctx)
BIO *OSSL_HTTP_REQ_CTX_exchange(OSSL_HTTP_REQ_CTX *rctx)
{
int rv;
@ -767,17 +791,6 @@ static BIO *ossl_http_req_ctx_transfer(OSSL_HTTP_REQ_CTX *rctx)
return rctx->mem;
}
/* Exchange ASN.1-encoded request and response via HTTP on (non-)blocking BIO */
ASN1_VALUE *OSSL_HTTP_REQ_CTX_sendreq_d2i(OSSL_HTTP_REQ_CTX *rctx,
const ASN1_ITEM *it)
{
if (rctx == NULL || it == NULL) {
ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
return BIO_mem_d2i(ossl_http_req_ctx_transfer(rctx), it);
}
static int update_timeout(int timeout, time_t start_time)
{
long elapsed_time;
@ -788,6 +801,15 @@ static int update_timeout(int timeout, time_t start_time)
return timeout <= elapsed_time ? -1 : timeout - elapsed_time;
}
OSSL_HTTP_REQ_CTX *OSSL_HTTP_open(const char *server, const char *port,
const char *proxy, const char *no_proxy,
int use_ssl, BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, int overall_timeout)
{
return NULL; /* TODO(3.0) expand */
}
/*-
* Exchange HTTP request and response with the given server.
* If req_mem == NULL then use GET and ignore content_type, else POST.
@ -815,16 +837,31 @@ static int update_timeout(int timeout, time_t start_time)
* The function should return NULL to indicate failure.
* After disconnect the modified BIO will be deallocated using BIO_free_all().
*/
BIO *OSSL_HTTP_transfer(const char *server, const char *port, const char *path,
int OSSL_HTTP_set_request(OSSL_HTTP_REQ_CTX *rctx, const char *path,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout, int keep_alive)
{
return 0; /* TODO(3.0) expand */
}
BIO *OSSL_HTTP_exchange(OSSL_HTTP_REQ_CTX *rctx, char **redirection_url)
{
return NULL; /* TODO(3.0) expand */
}
BIO *OSSL_HTTP_transfer(OSSL_HTTP_REQ_CTX **prctx,
const char *server, const char *port, const char *path,
int use_ssl, const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
int maxline, const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req_mem,
int maxline, unsigned long max_resp_len, int timeout,
const char *expected_ct, int expect_asn1,
char **redirection_url)
size_t max_resp_len, int timeout, int keep_alive)
{
char **redirection_url = (char **)prctx; /* TODO(3.0) fix when API approved */
time_t start_time = timeout > 0 ? time(NULL) : 0;
BIO *cbio; /* = bio if present, used as connection BIO if rbio is NULL */
OSSL_HTTP_REQ_CTX *rctx;
@ -892,12 +929,12 @@ BIO *OSSL_HTTP_transfer(const char *server, const char *port, const char *path,
rctx = ossl_http_req_ctx_new(cbio, rbio != NULL ? rbio : cbio,
!use_ssl && proxy != NULL, server, port, path,
headers, content_type, req_mem, maxline,
max_resp_len, update_timeout(timeout, start_time),
update_timeout(timeout, start_time),
expected_ct, expect_asn1);
if (rctx == NULL)
goto end;
resp = ossl_http_req_ctx_transfer(rctx);
resp = OSSL_HTTP_REQ_CTX_exchange(rctx);
if (resp == NULL) {
if (rctx->redirection_url != NULL) {
if (redirection_url == NULL)
@ -981,12 +1018,12 @@ static int redirection_ok(int n_redir, const char *old_url, const char *new_url)
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,
const STACK_OF(CONF_VALUE) *headers,
int maxline, unsigned long max_resp_len, int timeout,
const char *expected_ct, int expect_asn1)
int maxline, const STACK_OF(CONF_VALUE) *headers,
const char *expected_ct, int expect_asn1,
unsigned long max_resp_len, int timeout)
{
time_t start_time = timeout > 0 ? time(NULL) : 0;
char *current_url, *redirection_url;
char *current_url, *redirection_url = NULL;
int n_redirs = 0;
char *host;
char *port;
@ -1007,13 +1044,13 @@ BIO *OSSL_HTTP_get(const char *url, const char *proxy, const char *no_proxy,
break;
new_rpath:
resp = OSSL_HTTP_transfer(host, port, path, use_ssl, proxy, no_proxy,
resp = OSSL_HTTP_transfer((OSSL_HTTP_REQ_CTX **)&redirection_url, /* TODO(3.0) fix when API approved */
host, port, path, use_ssl, proxy, no_proxy,
bio, rbio,
bio_update_fn, arg, headers, NULL, NULL,
maxline, max_resp_len,
update_timeout(timeout, start_time),
bio_update_fn, arg, maxline, headers, NULL, NULL,
expected_ct, expect_asn1,
&redirection_url);
max_resp_len,
update_timeout(timeout, start_time), 0);
OPENSSL_free(path);
if (resp == NULL && redirection_url != NULL) {
if (redirection_ok(++n_redirs, current_url, redirection_url)) {
@ -1038,65 +1075,9 @@ BIO *OSSL_HTTP_get(const char *url, const char *proxy, const char *no_proxy,
return resp;
}
/* Get ASN.1-encoded data via HTTP from server at given URL */
ASN1_VALUE *OSSL_HTTP_get_asn1(const char *url,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
const ASN1_ITEM *rsp_it)
int OSSL_HTTP_close(OSSL_HTTP_REQ_CTX *rctx, int ok)
{
BIO *mem;
ASN1_VALUE *resp = NULL;
if (url == NULL || rsp_it == NULL) {
ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
mem = OSSL_HTTP_get(url, proxy, no_proxy, bio, rbio, bio_update_fn,
arg, headers, maxline, max_resp_len, timeout,
expected_ct, 1 /* expect_asn1 */);
resp = BIO_mem_d2i(mem /* may be NULL */, rsp_it);
BIO_free(mem);
return resp;
}
/* Post ASN.1-encoded request via HTTP to server return ASN.1 response */
ASN1_VALUE *OSSL_HTTP_post_asn1(const char *server, const char *port,
const char *path, int use_ssl,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type,
const ASN1_VALUE *req, const ASN1_ITEM *req_it,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
const ASN1_ITEM *rsp_it)
{
BIO *req_mem;
BIO *res_mem;
ASN1_VALUE *resp = NULL;
if (req == NULL) {
ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
/* remaining parameters are checked indirectly */
req_mem = ossl_http_asn1_item2bio(req_it, req);
res_mem = OSSL_HTTP_transfer(server, port, path, use_ssl, proxy, no_proxy,
bio, rbio,
bio_update_fn, arg, headers, content_type,
req_mem /* may be NULL */, maxline,
max_resp_len, timeout,
expected_ct, 1 /* expect_asn1 */, NULL);
BIO_free(req_mem);
resp = BIO_mem_d2i(res_mem /* may be NULL */, rsp_it);
BIO_free(res_mem);
return resp;
return 0; /* TODO(3.0) expand */
}
/* BASE64 encoder used for encoding basic proxy authentication credentials */

View File

@ -11,21 +11,6 @@
#ifndef OSSL_CRYPTO_HTTP_LOCAL_H
# define OSSL_CRYPTO_HTTP_LOCAL_H
# include <openssl/ocsp.h>
BIO *ossl_http_asn1_item2bio(const ASN1_ITEM *it, const ASN1_VALUE *val);
OSSL_HTTP_REQ_CTX
*ossl_http_req_ctx_new(BIO *wbio, BIO *rbio, int use_http_proxy,
const char *server, const char *port,
const char *path,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req_mem,
int maxline, unsigned long max_resp_len,
int timeout,
const char *expected_content_type,
int expect_asn1);
int ossl_http_use_proxy(const char *no_proxy, const char *server);
const char *ossl_http_adapt_proxy(const char *proxy, const char *no_proxy,
const char *server, int use_ssl);

View File

@ -16,17 +16,18 @@
OSSL_HTTP_REQ_CTX *OCSP_sendreq_new(BIO *io, const char *path,
const OCSP_REQUEST *req, int maxline)
{
OSSL_HTTP_REQ_CTX *rctx = NULL;
OSSL_HTTP_REQ_CTX *rctx = OSSL_HTTP_REQ_CTX_new(io, io, maxline);
if ((rctx = OSSL_HTTP_REQ_CTX_new(io, io,
maxline, 0 /* default max_resp_len */,
0 /* no timeout, blocking indefinitely */,
NULL, 1 /* expect_asn1 */)) == NULL)
if (rctx == NULL)
return NULL;
if (!OSSL_HTTP_REQ_CTX_set_request_line(rctx, 1 /* POST */, NULL, NULL, path))
goto err;
if (!OSSL_HTTP_REQ_CTX_set_expected(rctx,
NULL /* content_type */, 1 /* asn1 */,
0 /* timeout */, 0 /* keep_alive */))
goto err;
if (req != NULL
&& !OSSL_HTTP_REQ_CTX_set1_req(rctx, "application/ocsp-request",
ASN1_ITEM_rptr(OCSP_REQUEST),
@ -40,23 +41,19 @@ OSSL_HTTP_REQ_CTX *OCSP_sendreq_new(BIO *io, const char *path,
return NULL;
}
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OSSL_HTTP_REQ_CTX *rctx)
{
*presp = (OCSP_RESPONSE *)
OSSL_HTTP_REQ_CTX_sendreq_d2i(rctx, ASN1_ITEM_rptr(OCSP_RESPONSE));
return *presp != NULL;
}
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, const char *path, OCSP_REQUEST *req)
{
OCSP_RESPONSE *resp = NULL;
OSSL_HTTP_REQ_CTX *ctx;
BIO *mem;
ctx = OCSP_sendreq_new(b, path, req, -1 /* default max resp line length */);
if (ctx == NULL)
return NULL;
OCSP_sendreq_nbio(&resp, ctx);
mem = OSSL_HTTP_REQ_CTX_exchange(ctx);
resp = (OCSP_RESPONSE *)
ASN1_item_d2i_bio(ASN1_ITEM_rptr(OCSP_RESPONSE), mem, NULL);
BIO_free(mem);
/* this indirectly calls ERR_clear_error(): */
OSSL_HTTP_REQ_CTX_free(ctx);

View File

@ -75,11 +75,15 @@ int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx)
static ASN1_VALUE *simple_get_asn1(const char *url, BIO *bio, BIO *rbio,
int timeout, const ASN1_ITEM *it)
{
return OSSL_HTTP_get_asn1(url, NULL, NULL /* no proxy used */, bio,
rbio, NULL /* no callback for SSL/TLS */, NULL,
NULL /* headers */, 1024 /* maxline */,
0 /* max_resp_len */, timeout,
NULL /* expected_content_type */, it);
BIO *mem = OSSL_HTTP_get(url, NULL /* proxy */, NULL /* no_proxy */,
bio, rbio, NULL /* cb */ , NULL /* arg */,
1024 /* buf_size */, NULL /* headers */,
NULL /* expected_ct */, 1 /* expect_asn1 */,
HTTP_DEFAULT_MAX_RESP_LEN, timeout);
ASN1_VALUE *res = ASN1_item_d2i_bio(it, mem, NULL);
BIO_free(mem);
return res;
}
X509 *X509_load_http(const char *url, BIO *bio, BIO *rbio, int timeout)

View File

@ -52,6 +52,7 @@ Message transfer options:
[B<-proxy> I<[http[s]://][userinfo@]host[:port][/path][?query][#fragment]>]
[B<-no_proxy> I<addresses>]
[B<-recipient> I<name>]
[B<-keep_alive> I<value>]
[B<-msg_timeout> I<seconds>]
[B<-total_timeout> I<seconds>]
@ -488,11 +489,20 @@ as far as any of those is present, else the NULL-DN as last resort.
The argument must be formatted as I</type0=value0/type1=value1/type2=...>.
For details see the description of the B<-subject> option.
=item B<-keep_alive> I<value>
If the given value is 0 then HTTP connections are not kept open
after receiving a response, which is the default behavior for HTTP 1.0.
If the value is 1 or 2 then persistent connections are requested.
If the value is 2 then persistent connections are required,
i.e., in case the server does not grant them an error occurs.
The default value is 1, which means preferring to keep the connection open.
=item B<-msg_timeout> I<seconds>
Number of seconds (or 0 for infinite) a CMP request-response message round trip
is allowed to take before a timeout error is returned.
Default is 120.
Default is to use the B<-total_timeout> setting.
=item B<-total_timeout> I<seconds>

View File

@ -31,7 +31,7 @@ ASN1_item_i2d_mem_bio() returns a pointer to a memory BIO or NULL on error.
=head1 HISTORY
The functions described here were added in OpenSSL 3.0.
ASN1_item_i2d_mem_bio() was added in OpenSSL 3.0.
=head1 COPYRIGHT

View File

@ -18,10 +18,7 @@ OCSP_REQ_CTX_set1_req
#include <openssl/ocsp.h>
OSSL_HTTP_REQ_CTX *OCSP_sendreq_new(BIO *io, const char *path,
const OCSP_REQUEST *req, int maxline);
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OSSL_HTTP_REQ_CTX *rctx);
const OCSP_REQUEST *req, int buf_size);
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *io, const char *path, OCSP_REQUEST *req);
Deprecated since OpenSSL 3.0, can be hidden entirely by defining
@ -29,12 +26,12 @@ B<OPENSSL_API_COMPAT> with a suitable version value, see
L<openssl_user_macros(7)>:
typedef OSSL_HTTP_REQ_CTX OCSP_REQ_CTX;
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OSSL_HTTP_REQ_CTX *rctx);
int OCSP_REQ_CTX_i2d(OCSP_REQ_CT *rctx, const ASN1_ITEM *it, ASN1_VALUE *req);
int OCSP_REQ_CTX_add1_header(OCSP_REQ_CT *rctx,
const char *name, const char *value);
void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx);
void OCSP_set_max_response_length(OCSP_REQ_CT *rctx,
unsigned long len);
void OCSP_set_max_response_length(OCSP_REQ_CT *rctx, unsigned long len);
int OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, const OCSP_REQUEST *req);
=head1 DESCRIPTION
@ -42,28 +39,32 @@ L<openssl_user_macros(7)>:
These functions perform an OCSP POST request / response transfer over HTTP,
using the HTTP request functions described in L<OSSL_HTTP_REQ_CTX(3)>.
The function OCSP_sendreq_new() builds a complete B<OSSL_HTTP_REQ_CTX>
structure using connection B<BIO> I<io>, the URL path I<path>, the OCSP
request I<req>, and with a response header maximum line length of I<maxline>.
If I<maxline> is zero a default value of 4k is used.
The function OCSP_sendreq_new() builds a complete B<OSSL_HTTP_REQ_CTX> structure
with the B<BIO> I<io> to be used for requests and reponse, the URL path I<path>,
optionally the OCSP request I<req>, and a response header maximum line length
of I<buf_size>. If I<buf_size> is zero a default value of 4KiB is used.
The I<req> may be set to NULL and provided later using OCSP_REQ_CTX_set1_req()
or L<OSSL_HTTP_REQ_CTX_set1_req(3)> .
or L<OSSL_HTTP_REQ_CTX_set1_req(3)>.
The I<io> and I<path> arguments to OCSP_sendreq_new() correspond to the
components of the URL.
For example if the responder URL is C<http://example.com/ocspreq> the BIO
I<io> should be connected to host C<example.com> on port 80 and I<path>
I<io> should haven been connected to host C<example.com> on port 80 and I<path>
should be set to C</ocspreq>.
OCSP_sendreq_nbio() performs I/O on the OCSP request context I<rctx>.
When the operation is complete it assigns the response, a pointer to a
B<OCSP_RESPONSE> structure, in I<*presp>.
OCSP_sendreq_nbio() attempts to send the request prepared in I<rctx>
and to gather the response via HTTP, using the BIO I<io> and I<path>
that were given when calling OCSP_sendreq_new().
If the operation gets completed it assigns the response,
a pointer to a B<OCSP_RESPONSE> structure, in I<*presp>.
The function may need to be called again if its result is -1, which indicates
L<BIO_should_retry(3)>. In such a case it is advisable to sleep a little in
between, using L<BIO_wait(3)> on the read BIO to prevent a busy loop.
OCSP_sendreq_bio() is the same as a call to OCSP_sendreq_new() followed by
OCSP_sendreq_nbio() and then OCSP_REQ_CTX_free() in a single call, with a
OCSP_sendreq_bio() combines OCSP_sendreq_new() with as many calls of
OCSP_sendreq_nbio() as needed and then OCSP_REQ_CTX_free(), with a
response header maximum line length 4k. It waits indefinitely on a response.
It does not support setting a timeout or adding headers and is retained
for compatibility; use OCSP_sendreq_nbio() instead.
for compatibility; use L<OSSL_HTTP_transfer(3)> instead.
OCSP_REQ_CTX_i2d(rctx, it, req) is equivalent to the following:
@ -88,15 +89,14 @@ L<OSSL_HTTP_REQ_CTX_set_max_response_length(3)>.
OCSP_sendreq_new() returns a valid B<OSSL_HTTP_REQ_CTX> structure or NULL
if an error occurred.
OCSP_sendreq_nbio(), OCSP_REQ_CTX_i2d(), and OCSP_REQ_CTX_set1_req()
return 1 for success and 0 for failure.
OCSP_sendreq_nbio() returns 1 for success, 0 on error, -1 if retry is needed.
OCSP_sendreq_bio() returns the B<OCSP_RESPONSE> structure sent by the
responder or NULL if an error occurred.
=head1 SEE ALSO
L<OSSL_HTTP_REQ_CTX(3)>
L<OSSL_HTTP_REQ_CTX(3)>, L<OSSL_HTTP_transfer(3)>,
L<OCSP_cert_to_id(3)>,
L<OCSP_request_add1_nonce(3)>,
L<OCSP_REQUEST_new(3)>,

View File

@ -7,11 +7,15 @@ OSSL_HTTP_REQ_CTX_new,
OSSL_HTTP_REQ_CTX_free,
OSSL_HTTP_REQ_CTX_set_request_line,
OSSL_HTTP_REQ_CTX_add1_header,
OSSL_HTTP_REQ_CTX_set_expected,
OSSL_HTTP_REQ_CTX_set1_req,
OSSL_HTTP_REQ_CTX_nbio,
OSSL_HTTP_REQ_CTX_sendreq_d2i,
OSSL_HTTP_REQ_CTX_nbio_d2i,
OSSL_HTTP_REQ_CTX_exchange,
OSSL_HTTP_REQ_CTX_get0_mem_bio,
OSSL_HTTP_REQ_CTX_set_max_response_length
OSSL_HTTP_REQ_CTX_get_resp_len,
OSSL_HTTP_REQ_CTX_set_max_response_length,
OSSL_HTTP_is_alive
- HTTP client low-level functions
=head1 SYNOPSIS
@ -20,11 +24,7 @@ OSSL_HTTP_REQ_CTX_set_max_response_length
typedef struct ossl_http_req_ctx_st OSSL_HTTP_REQ_CTX;
OSSL_HTTP_REQ_CTX *OSSL_HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio,
int maxline, unsigned long max_resp_len,
int timeout,
const char *expected_content_type,
int expect_asn1);
OSSL_HTTP_REQ_CTX *OSSL_HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio, int buf_size);
void OSSL_HTTP_REQ_CTX_free(OSSL_HTTP_REQ_CTX *rctx);
int OSSL_HTTP_REQ_CTX_set_request_line(OSSL_HTTP_REQ_CTX *rctx, int method_POST,
@ -33,42 +33,41 @@ OSSL_HTTP_REQ_CTX_set_max_response_length
int OSSL_HTTP_REQ_CTX_add1_header(OSSL_HTTP_REQ_CTX *rctx,
const char *name, const char *value);
int OSSL_HTTP_REQ_CTX_set_expected(OSSL_HTTP_REQ_CTX *rctx,
const char *content_type, int asn1,
int timeout, int keep_alive);
int OSSL_HTTP_REQ_CTX_set1_req(OSSL_HTTP_REQ_CTX *rctx, const char *content_type,
const ASN1_ITEM *it, ASN1_VALUE *req);
const ASN1_ITEM *it, const ASN1_VALUE *req);
int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx);
ASN1_VALUE *OSSL_HTTP_REQ_CTX_sendreq_d2i(OSSL_HTTP_REQ_CTX *rctx,
const ASN1_ITEM *it);
int OSSL_HTTP_REQ_CTX_nbio_d2i(OSSL_HTTP_REQ_CTX *rctx,
ASN1_VALUE **pval, const ASN1_ITEM *it);
BIO *OSSL_HTTP_REQ_CTX_exchange(OSSL_HTTP_REQ_CTX *rctx);
BIO *OSSL_HTTP_REQ_CTX_get0_mem_bio(const OSSL_HTTP_REQ_CTX *rctx);
size_t OSSL_HTTP_REQ_CTX_get_resp_len(const OSSL_HTTP_REQ_CTX *rctx);
void OSSL_HTTP_REQ_CTX_set_max_response_length(OSSL_HTTP_REQ_CTX *rctx,
unsigned long len);
int OSSL_HTTP_is_alive(const OSSL_HTTP_REQ_CTX *rctx);
=head1 DESCRIPTION
B<OSSL_HTTP_REQ_CTX> is a context structure for an HTTP request, used to
collect all the necessary data to perform that request.
B<OSSL_HTTP_REQ_CTX> is a context structure for an HTTP request and response,
used to collect all the necessary data to perform that request.
This file documents low-level HTTP functions rarely used directly. High-level
HTTP client functions like L<OSSL_HTTP_get(3)> and L<OSSL_HTTP_transfer(3)>
should be preferred.
OSSL_HTTP_REQ_CTX_new() allocates a new HTTP request context structure,
which gets populated with the B<BIO> to send the request to (I<wbio>),
the B<BIO> to read the response from (I<rbio>, which may be equal to I<wbio>),
the maximum expected response header line length (I<maxline>, where a value <= 0
indicates that the B<HTTP_DEFAULT_MAX_LINE_LENGTH> of 4KiB should be used;
this length is also used as the number of content bytes read at a time),
the maximum allowed response content length (I<max_resp_len>, where 0 means
that the B<HTTP_DEFAULT_MAX_RESP_LEN> is used, which currently is 100 KiB),
a response timeout measure in seconds (I<timeout>,
where 0 indicates no timeout, i.e., waiting indefinitely),
the expected MIME content type of the response (I<expected_content_type>,
which may be NULL for no expectation),
and a flag indicating that the response is expected to be
a DER encoded ASN.1 structure (I<expect_asn1>).
which gets populated with the B<BIO> to write/send the request to (I<wbio>),
the B<BIO> to read/receive the response from (I<rbio>, which may be equal to
I<wbio>), and the maximum expected response header line length I<buf_size>.
A value <= 0 indicates that
the B<HTTP_DEFAULT_MAX_LINE_LENGTH> of 4KiB should be used.
I<buf_size> is also used as the number of content bytes that are read at a time.
The allocated context structure is also populated with an internal allocated
memory B<BIO>, which collects the HTTP request and additional headers as text.
The returned context should only be used for a single HTTP request/response.
OSSL_HTTP_REQ_CTX_free() frees up the HTTP request context I<rctx>.
The I<wbio> and I<rbio> are not free'd and it is up to the application
@ -87,33 +86,71 @@ For example, to add a C<Host> header for C<example.com> you would call:
OSSL_HTTP_REQ_CTX_add1_header(ctx, "Host", "example.com");
OSSL_HTTP_REQ_CTX_set_expected() optionally sets in I<rctx> some expectations
of the HTTP client on the response.
Due to the structure of an HTTP request, if the I<keep_alive> argument is
nonzero the function must be used before calling OSSL_HTTP_REQ_CTX_set1_req().
If the I<content_type> parameter
is not NULL then the client will check that the given content type string
is included in the HTTP header of the response and return an error if not.
If the I<asn1> parameter is nonzero a structure in ASN.1 encoding will be
expected as the response content and input streaming is disabled. This means
that an ASN.1 sequence header is required, its length field is checked, and
OSSL_HTTP_REQ_CTX_get0_mem_bio() should be used to get the buffered response.
Else any form of input is allowed without length checks, which is the default.
In this case the BIO given as I<rbio> argument to OSSL_HTTP_REQ_CTX_new() should
be used directly to read the response contents, which may support streaming.
If the I<timeout> parameter is > 0 this indicates the maximum number of seconds
the subsequent HTTP transfer (sending the request and receiving a response)
is allowed to take.
A value <= 0 enables waiting indefinitely, i.e., no timeout can occur.
This is the default.
If the I<keep_alive> parameter is 0, which is the default, the connection is not
kept open after receiving a response. This is the default behavior for HTTP 1.0.
If the value is 1 or 2 then a persistent connection is requested.
If the value is 2 then a persistent connection is required,
i.e., an error occurs in case the server does not grant it.
OSSL_HTTP_REQ_CTX_set1_req() is to be used if and only if the I<method_POST>
parameter in the OSSL_HTTP_REQ_CTX_set_request_line() call was 1.
parameter in the OSSL_HTTP_REQ_CTX_set_request_line() call was 1
and an ASN.1-encoded request should be sent, which does not support streaming.
It finalizes the HTTP request context by adding the DER encoding of I<req>,
using the ASN.1 template I<it> to do the encoding.
The HTTP header C<Content-Length> is filled out with the length of the request.
If I<content_type> isn't NULL,
the HTTP header C<Content-Type> is also added with its content as value.
the HTTP header C<Content-Type> is also added with the given string value.
All of this ends up in the internal memory B<BIO>.
OSSL_HTTP_REQ_CTX_nbio() attempts to send the request prepared I<rctx>
and gathering the response via HTTP, using the I<rbio> and I<wbio>
OSSL_HTTP_REQ_CTX_nbio() attempts to send the request prepared in I<rctx>
and to gather the response via HTTP, using the I<wbio> and I<rbio>
that were given when calling OSSL_HTTP_REQ_CTX_new().
When successful, the contents of the internal memory B<BIO> contains
the contents of the HTTP response, without the response headers.
It may need to be called again if its result is -1, which indicates
The function may need to be called again if its result is -1, which indicates
L<BIO_should_retry(3)>. In such a case it is advisable to sleep a little in
between using L<BIO_wait(3)> on the read BIO to prevent a busy loop.
between, using L<BIO_wait(3)> on the read BIO to prevent a busy loop.
OSSL_HTTP_REQ_CTX_sendreq_d2i() calls OSSL_HTTP_REQ_CTX_nbio(), possibly
several times until a timeout is reached, and DER decodes the received
response using the ASN.1 template I<it>.
OSSL_HTTP_REQ_CTX_nbio_d2i() is like OSSL_HTTP_REQ_CTX_nbio() but on successs
in addition parses the response, which must be a DER-encoded ASN.1 structure,
using the ASN.1 template I<it> and places the result in I<*pval>.
OSSL_HTTP_REQ_CTX_exchange() calls OSSL_HTTP_REQ_CTX_nbio() as often as needed
in order to exchange a request and response or until a timeout is reached.
If successful and an ASN.1-encoded response was expected, the response contents
should be read via the BIO returned by OSSL_HTTP_REQ_CTX_get0_mem_bio().
Else the I<rbio> that was given when calling OSSL_HTTP_REQ_CTX_new()
represents the current state of reading the response.
If OSSL_HTTP_REQ_CTX_exchange() was successful, this BIO has been read past the
end of the response headers, such that the actual response contents can be read
via this BIO, which may support streaming.
OSSL_HTTP_REQ_CTX_get0_mem_bio() returns the internal memory B<BIO>.
Before sending the request, this could used to modify the HTTP request text.
I<Use with caution!>
After receiving a response via HTTP, the BIO represents
the current state of reading the response headers and contents.
After receiving a response via HTTP, the BIO represents the current state of
reading the response headers. If the response was expected to be ASN.1 encoded,
its contents can be read via this BIO, which does not support streaming.
OSSL_HTTP_REQ_CTX_get_resp_len() returns the size of the response contents
in I<rctx> if provided by the server as <Content-Length> header field, else 0.
OSSL_HTTP_REQ_CTX_set_max_response_length() sets the maximum allowed
response content length for I<rctx> to I<len>. If not set or I<len> is 0
@ -122,6 +159,18 @@ If the C<Content-Length> header is present and exceeds this value or
the content is an ASN.1 encoded structure with a length exceeding this value
or both length indications are present but disagree then an error occurs.
OSSL_HTTP_is_alive() can be used to query if the HTTP connection
given by I<rctx> is still alive, i.e., has not been closed.
It returns 0 if I<rctx> is NULL.
If the client application requested or required a persistent connection
and this was granted by the server, it can keep I<rctx> as long as it wants
to send further requests and OSSL_HTTP_is_alive() returns nonzero,
else it should call I<OSSL_HTTP_REQ_CTX_free(rctx)> or L<OSSL_HTTP_close(3)>.
In case the client application keeps I<rctx> 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 via I<rctx>.
=head1 WARNINGS
The server's response may be unexpected if the hostname that was used to
@ -155,7 +204,7 @@ and must be done exactly once in that case.
=back
When the request context is fully prepared, the HTTP exchange may be performed
with OSSL_HTTP_REQ_CTX_nbio() or OSSL_HTTP_REQ_CTX_sendreq_d2i().
with OSSL_HTTP_REQ_CTX_nbio() or OSSL_HTTP_REQ_CTX_exchange().
=head1 RETURN VALUES
@ -166,20 +215,36 @@ OSSL_HTTP_REQ_CTX_free() and OSSL_HTTP_REQ_CTX_set_max_response_length()
do not return values.
OSSL_HTTP_REQ_CTX_set_request_line(), OSSL_HTTP_REQ_CTX_add1_header(),
OSSL_HTTP_REQ_CTX_set1_req() and OSSL_HTTP_REQ_CTX_nbio
OSSL_HTTP_REQ_CTX_set1_req(), and OSSL_HTTP_REQ_CTX_set_expected()
return 1 for success and 0 for failure.
OSSL_HTTP_REQ_CTX_sendreq_d2i() returns a pointer to an B<ASN1_VALUE> for
success and NULL for failure.
OSSL_HTTP_REQ_CTX_nbio() and OSSL_HTTP_REQ_CTX_nbio_d2i()
return 1 for success, 0 on error or redirection, -1 if retry is needed.
OSSL_HTTP_REQ_CTX_get0_mem_bio() returns the internal memory B<BIO>.
OSSL_HTTP_REQ_CTX_exchange() and OSSL_HTTP_REQ_CTX_get0_mem_bio()
returns a pointer to a B<BIO> on success and NULL on failure.
OSSL_HTTP_REQ_CTX_get_resp_len() returns the size of the response contents
or 0 if not available or an error occurred.
OSSL_HTTP_is_alive() returns 1 if its argument is non-NULL
and the client requested a persistent connection
and the server did not disagree on keeping the connection open, else 0.
=head1 SEE ALSO
L<BIO_should_retry(3)>,
L<BIO_wait(3)>,
L<ASN1_item_d2i_bio(3)>,
L<ASN1_item_i2d_mem_bio(3)>,
L<OSSL_HTTP_open(3)>,
L<OSSL_HTTP_get(3)>,
L<OSSL_HTTP_transfer(3)>
L<OSSL_HTTP_transfer(3)>,
L<OSSL_HTTP_close(3)>
=head1 HISTORY
The functions described here were added in OpenSSL 3.0.
=head1 COPYRIGHT

View File

@ -2,13 +2,15 @@
=head1 NAME
OSSL_HTTP_get,
OSSL_HTTP_get_asn1,
OSSL_HTTP_post_asn1,
OSSL_HTTP_transfer,
OSSL_HTTP_open,
OSSL_HTTP_bio_cb_t,
OSSL_HTTP_proxy_connect
- http client functions
OSSL_HTTP_proxy_connect,
OSSL_HTTP_set_request,
OSSL_HTTP_exchange,
OSSL_HTTP_get,
OSSL_HTTP_transfer,
OSSL_HTTP_close
- HTTP client high-level functions
=head1 SYNOPSIS
@ -16,91 +18,53 @@ OSSL_HTTP_proxy_connect
typedef BIO *(*OSSL_HTTP_bio_cb_t)(BIO *bio, void *arg,
int connect, int detail);
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,
const STACK_OF(CONF_VALUE) *headers,
int maxline, unsigned long max_resp_len, int timeout,
const char *expected_ct, int expect_asn1);
ASN1_VALUE *OSSL_HTTP_get_asn1(const char *url,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
const ASN1_ITEM *rsp_it);
ASN1_VALUE *OSSL_HTTP_post_asn1(const char *server, const char *port,
const char *path, int use_ssl,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type,
const ASN1_VALUE *req, const ASN1_ITEM *req_it,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
const ASN1_ITEM *rsp_it);
BIO *OSSL_HTTP_transfer(const char *server, const char *port, const char *path,
int use_ssl, const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req_mem,
int maxline, unsigned long max_resp_len, int timeout,
const char *expected_ct, int expect_asn1,
char **redirection_url);
OSSL_HTTP_REQ_CTX *OSSL_HTTP_open(const char *server, const char *port,
const char *proxy, const char *no_proxy,
int use_ssl, BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, int overall_timeout);
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);
int OSSL_HTTP_set_request(OSSL_HTTP_REQ_CTX *rctx, const char *path,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout, int keep_alive);
BIO *OSSL_HTTP_exchange(OSSL_HTTP_REQ_CTX *rctx, char **redirection_url);
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,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout);
BIO *OSSL_HTTP_transfer(OSSL_HTTP_REQ_CTX **prctx,
const char *server, const char *port,
const char *path, int use_ssl,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout, int keep_alive);
int OSSL_HTTP_close(OSSL_HTTP_REQ_CTX *rctx, int ok);
=head1 DESCRIPTION
OSSL_HTTP_get() uses HTTP GET to obtain data (of any type) from the given I<url>
and returns it as a memory BIO.
If the schema component of the I<url> is C<https> a TLS connection is requested
and the I<bio_update_fn> parameter, described below, must be provided.
Any userinfo and fragment components in the I<url> are ignored.
Any query component is handled as part of the path component.
OSSL_HTTP_open() initiates an HTTP session using the I<bio> argument if not
NULL, else by connecting to a given I<server> optionally via a I<proxy>.
OSSL_HTTP_get_asn1() is like OSSL_HTTP_get() but in addition
parses the received contents (e.g., an X.509 certificate)
as an ASN.1 DER encoded value with the expected structure specified by I<rsp_it>
and returns it on success as a pointer to I<ASN1_VALUE>.
OSSL_HTTP_post_asn1() is like OSSL_HTTP_get_asn1() but uses the HTTP POST method
to send a request I<req> with the ASN.1 structure defined in I<req_it> and the
given I<content_type> to the given I<server> and optional I<port> and I<path>.
If I<use_ssl> is nonzero a TLS connection is requested and the I<bio_update_fn>
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 I<path> parameter is NULL it defaults to "/".
If I<use_ssl> is nonzero a TLS connection is requested
and the I<bio_update_fn> parameter, described below, must be provided.
If I<req_mem> 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 I<content_type>.
The optional list I<headers> may contain additional custom HTTP header lines.
If I<req_mem> is NULL (i.e., the HTTP method is GET) and I<redirection_url>
is not NULL the latter pointer is used to provide any new location that
the server may return with HTTP code 301 (MOVED_PERMANENTLY) or 302 (FOUND).
In this case the caller is responsible for deallocating this URL with
L<OPENSSL_free(3)>.
The above functions have the following parameters in common.
Typically the OpenSSL build supports sockets
and the I<bio> and I<rbio> parameters are both NULL.
In this case the client creates a network BIO internally
for connecting to the given I<server>
at the specified I<port> (if any, defaulting to 80 for HTTP or 443 for HTTPS),
optionally via a I<proxy> (respecting I<no_proxy>) as described below.
Then the client uses this internal BIO for exchanging the request and response.
If I<bio> is given and I<rbio> is NULL then the client uses this I<bio> instead.
Typically the OpenSSL build supports sockets and the I<bio> parameter is NULL.
In this case I<rbio> must be NULL as well, and the
library creates a network BIO internally for connecting to the given I<server>
at the specified I<port> if any, defaulting to 80 for HTTP or 443 for HTTPS.
Then this internal BIO is used for setting up a connection
and for exchanging one or more request and response.
If I<bio> is given and I<rbio> is NULL then this I<bio> is used instead.
If both I<bio> and I<rbio> are given (which may be memory BIOs for instance)
then no explicit connection is attempted,
I<bio> is used for writing the request, and I<rbio> for reading the response.
then no explicit connection is set up, but
I<bio> is used for writing requests and I<rbio> for reading responses.
As soon as the client has flushed I<bio> the server must be ready to provide
a response or indicate a waiting condition via I<rbio>.
@ -121,33 +85,12 @@ 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.
The I<maxline> parameter specifies the response header maximum line length,
where a value <= 0 indicates that the B<HTTP_DEFAULT_MAX_LINE_LENGTH> of 4KiB
should be used.
This length is also used as the number of content bytes that are read at a time.
The I<max_resp_len> parameter specifies the maximum response length,
where 0 indicates B<HTTP_DEFAULT_MAX_RESP_LEN>, which currently is 100 KiB.
If I<use_ssl> is nonzero a TLS connection is requested
and the I<bio_update_fn> parameter must be provided.
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 I<expect_asn1> parameter is nonzero.
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.
If the parameter I<expected_ct>
is not NULL then the HTTP client checks that the given content type string
is included in the HTTP header of the response and returns an error if not.
If the I<timeout> parameter is > 0 this indicates the maximum number of seconds
to wait until the transfer is complete.
A value of 0 enables waiting indefinitely,
while a value < 0 immediately leads to a timeout condition.
The optional parameter I<bio_update_fn> with its optional argument I<arg> may
be used to modify the connection BIO used by the HTTP client (and cannot be
used when both I<bio> and I<rbio> are given).
The parameter I<bio_update_fn>, which is optional if I<use_ssl> is 0,
may be used to modify the connection BIO used by the HTTP client,
but cannot be used when both I<bio> and I<rbio> are given.
I<bio_update_fn> is a BIO connect/disconnect callback function with prototype
BIO *(*OSSL_HTTP_bio_cb_t)(BIO *bio, void *arg, int connect, int detail)
@ -157,7 +100,7 @@ whereby it may make use of a custom defined argument I<arg>,
which may for instance refer to an I<SSL_CTX> structure.
During connection establishment, just after calling BIO_do_connect_retry(),
the function is invoked with the I<connect> argument being 1 and the I<detail>
argument being 1 if HTTPS is requested, i.e., SSL/TLS should be enabled.
argument being 1 if HTTPS is requested, i.e., SSL/TLS should be enabled, else 0.
On disconnect I<connect> is 0 and I<detail> is 1 if no error occurred, else 0.
For instance, on connect the function may prepend a TLS BIO to implement HTTPS;
after disconnect it may do some diagnostic output and/or specific cleanup.
@ -166,10 +109,10 @@ 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)
{
SSL_CTX *ctx = (SSL_CTX *)arg;
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 */
@ -179,6 +122,16 @@ 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().
The I<buf_size> parameter specifies the response header maximum line length.
A value <= 0 indicates that
the B<HTTP_DEFAULT_MAX_LINE_LENGTH> of 4KiB should be used.
I<buf_size> is also used as the number of content bytes that are read at a time.
If the I<overall_timeout> parameter is > 0 this indicates the maximum number of
seconds the overall HTTP transfer (i.e., connection setup if needed,
sending requests, and receiving responses) is allowed to take until completion.
A value <= 0 enables waiting indefinitely, i.e., no timeout.
OSSL_HTTP_proxy_connect() may be used by an above BIO connect callback function
to set up an SSL/TLS connection via an HTTPS proxy.
It promotes the given BIO I<bio> representing a connection
@ -186,11 +139,86 @@ pre-established with a TLS proxy using the HTTP CONNECT method,
optionally using proxy client credentials I<proxyuser> and I<proxypass>,
to connect with TLS protection ultimately to I<server> and I<port>.
If the I<port> argument is NULL or the empty string it defaults to "443".
The I<timeout> parameter is used as described above.
If the I<timeout> parameter is > 0 this indicates the maximum number of
seconds the connection setup is allowed to take.
A value <= 0 enables waiting indefinitely, i.e., no timeout.
Since this function is typically called by applications such as
L<openssl-s_client(1)> it uses the I<bio_err> and I<prog> parameters (unless
NULL) to print additional diagnostic information in a user-oriented way.
OSSL_HTTP_set_request() sets up in I<rctx> the request header and content data
and expectations on the response using the following parameters.
If I<path> is NULL it defaults to "/".
If I<req> is NULL the HTTP GET method will be used to send the request
else HTTP POST with the contents of I<req> and optional I<content_type>, where
the length of the data in I<req> does not need to be determined in advance: the
BIO will be read on-the-fly while sending the request, which supports streaming.
The optional list I<headers> may contain additional custom HTTP header lines.
If the parameter I<expected_content_type>
is not NULL then the client will check that the given content type string
is included in the HTTP header of the response and return an error if not.
If the I<expect_asn1> parameter is nonzero,
a structure in ASN.1 encoding will be expected as response content.
The I<max_resp_len> parameter specifies the maximum allowed
response content length, where the value 0 indicates no limit.
If the I<timeout> parameter is > 0 this indicates the maximum number of seconds
the subsequent HTTP transfer (sending the request and receiving a response)
is allowed to take.
A value of 0 enables waiting indefinitely, i.e., no timeout.
A value < 0 indicates that the I<overall_timeout> parameter value given
when opening the HTTP transfer will be used instead.
If I<keep_alive> is 0 the connection is not kept open
after receiving a response, which is the default behavior for HTTP 1.0.
If the value is 1 or 2 then a persistent connection is requested.
If the value is 2 then a persistent connection is required,
i.e., an error occurs in case the server does not grant it.
OSSL_HTTP_exchange() exchanges any form of HTTP request and response
as specified by I<rctx>, which must include both connection and request data,
typically set up using OSSL_HTTP_open() and OSSL_HTTP_set_request().
It implements the core of the functions described below.
If the HTTP method is GET and I<redirection_url>
is not NULL the latter pointer is used to provide any new location that
the server may return with HTTP code 301 (MOVED_PERMANENTLY) or 302 (FOUND).
In this case the function returns NULL and the caller is
responsible for deallocating the URL with L<OPENSSL_free(3)>.
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 any given maximum response length.
On receiving a response, the function returns the contents as a memory BIO,
which does not support streaming, in case an ASN.1-encoded response is expected.
Else it returns directly the read BIO that holds the response contents,
which allows a response of indefinite length and may support streaming.
OSSL_HTTP_get() uses HTTP GET to obtain data from I<bio> if non-NULL,
else from the server contained in the I<url>, and returns it as a BIO.
It supports redirection via HTTP status code 301 or 302. It is meant for
transfers with a single round trip, so does not support persistent connections.
If I<bio> is non-NULL, any host and port components in the I<url> are not used
for connecting but the hostname is used, as usual, for the C<Host> header.
Any userinfo and fragment components in the I<url> are ignored.
Any query component is handled as part of the path component.
If the scheme component of the I<url> is C<https> a TLS connection is requested
and the I<bio_update_fn>, as described for OSSL_HTTP_open(), must be provided.
Also the remaining parameters are interpreted as described for OSSL_HTTP_open()
and OSSL_HTTP_set_request(), respectively.
OSSL_HTTP_transfer() exchanges an HTTP request and response
over a connection managed via I<prctx> without supporting redirection.
It combines OSSL_HTTP_open(), OSSL_HTTP_set_request(), OSSL_HTTP_exchange(),
and OSSL_HTTP_close().
If I<prctx> is not NULL it reuses any open connection represented by a non-NULL
I<*prctx>. It keeps the connection open if a persistent connection is requested
or required and this was granted by the server, else it closes the connection
and assigns NULL to I<*prctx>.
The remaining parameters are interpreted as described for OSSL_HTTP_open()
and OSSL_HTTP_set_request(), respectively.
OSSL_HTTP_close() closes the connection and releases I<rctx>.
The I<ok> parameter is passed to any BIO update function
given during setup as described above for OSSL_HTTP_open().
=head1 NOTES
The names of the environment variables used by this implementation:
@ -200,23 +228,29 @@ other HTTP client implementations such as wget, curl, and git.
=head1 RETURN VALUES
On success, OSSL_HTTP_get(), OSSL_HTTP_get_asn1(), OSSL_HTTP_post_asn1(), and
OSSL_HTTP_transfer() return a memory BIO containing the data received via HTTP.
This must be freed by the caller. On failure, NULL is returned.
OSSL_HTTP_open() returns on success a B<OSSL_HTTP_REQ_CTX>, else NULL.
OSSL_HTTP_proxy_connect() and OSSL_HTTP_set_request()
return 1 on success, 0 on error.
On success, OSSL_HTTP_exchange(), OSSL_HTTP_get(), and OSSL_HTTP_transfer()
return a memory BIO containing the data received if an ASN.1-encoded response
is expected, else a BIO that may support streaming.
The BIO must be freed by the caller.
On failure, they return NULL.
Failure conditions include connection/transfer timeout, parse errors, etc.
OSSL_HTTP_proxy_connect() returns 1 on success, 0 on error.
OSSL_HTTP_close() returns 0 if anything went wrong while disconnecting, else 1.
=head1 SEE ALSO
L<OSSL_HTTP_parse_url(3)>
L<BIO_set_conn_port(3)>
L<OSSL_HTTP_parse_url(3)>, L<BIO_set_conn_port(3)>
L<ASN1_item_i2d_mem_bio(3)>, L<ASN1_item_d2i_bio(3)>,
L<OSSL_HTTP_is_alive(3)>
=head1 HISTORY
OSSL_HTTP_get(), OSSL_HTTP_get_asn1(), OSSL_HTTP_post_asn1(),
OSSL_HTTP_transfer(), and OSSL_HTTP_proxy_connect()
were added in OpenSSL 3.0.
All the functions described here were added in OpenSSL 3.0.
=head1 COPYRIGHT

View File

@ -49,7 +49,7 @@ Error conditions include connection/transfer timeout, parse errors, etc.
=head1 SEE ALSO
L<OSSL_HTTP_get_asn1(3)>
L<OSSL_HTTP_get(3)>
=head1 HISTORY

View File

@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2020-2021 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

View File

@ -262,25 +262,29 @@ void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg);
OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq);
void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx);
/* various CMP options: */
/* CMP general options: */
# define OSSL_CMP_OPT_LOG_VERBOSITY 0
# define OSSL_CMP_OPT_MSG_TIMEOUT 1
# define OSSL_CMP_OPT_TOTAL_TIMEOUT 2
# define OSSL_CMP_OPT_VALIDITY_DAYS 3
# define OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT 4
# define OSSL_CMP_OPT_SUBJECTALTNAME_CRITICAL 5
# define OSSL_CMP_OPT_POLICIES_CRITICAL 6
# define OSSL_CMP_OPT_POPO_METHOD 7
# define OSSL_CMP_OPT_DIGEST_ALGNID 8
# define OSSL_CMP_OPT_OWF_ALGNID 9
# define OSSL_CMP_OPT_MAC_ALGNID 10
# define OSSL_CMP_OPT_REVOCATION_REASON 11
# define OSSL_CMP_OPT_IMPLICIT_CONFIRM 12
# define OSSL_CMP_OPT_DISABLE_CONFIRM 13
# define OSSL_CMP_OPT_UNPROTECTED_SEND 14
# define OSSL_CMP_OPT_UNPROTECTED_ERRORS 15
# define OSSL_CMP_OPT_IGNORE_KEYUSAGE 16
# define OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR 17
/* CMP transfer options: */
# define OSSL_CMP_OPT_KEEP_ALIVE 10
# define OSSL_CMP_OPT_MSG_TIMEOUT 11
# define OSSL_CMP_OPT_TOTAL_TIMEOUT 12
/* CMP request options: */
# define OSSL_CMP_OPT_VALIDITY_DAYS 20
# define OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT 21
# define OSSL_CMP_OPT_SUBJECTALTNAME_CRITICAL 22
# define OSSL_CMP_OPT_POLICIES_CRITICAL 23
# define OSSL_CMP_OPT_POPO_METHOD 24
# define OSSL_CMP_OPT_IMPLICIT_CONFIRM 25
# define OSSL_CMP_OPT_DISABLE_CONFIRM 26
# define OSSL_CMP_OPT_REVOCATION_REASON 27
/* CMP protection options: */
# define OSSL_CMP_OPT_UNPROTECTED_SEND 30
# define OSSL_CMP_OPT_UNPROTECTED_ERRORS 31
# define OSSL_CMP_OPT_OWF_ALGNID 32
# define OSSL_CMP_OPT_MAC_ALGNID 33
# define OSSL_CMP_OPT_DIGEST_ALGNID 34
# define OSSL_CMP_OPT_IGNORE_KEYUSAGE 35
# define OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR 36
int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val);
int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt);
/* CMP-specific callback for logging and outputting the error queue: */

View File

@ -23,8 +23,6 @@
extern "C" {
# endif
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"://"
@ -38,63 +36,64 @@ typedef BIO *(*OSSL_HTTP_bio_cb_t)(BIO *bio, void *arg, int connect, int detail)
#define HTTP_DEFAULT_MAX_LINE_LENGTH (4 * 1024)
#define HTTP_DEFAULT_MAX_RESP_LEN (100 * 1024)
OSSL_HTTP_REQ_CTX *OSSL_HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
int expect_asn1);
/* Low-level HTTP API */
OSSL_HTTP_REQ_CTX *OSSL_HTTP_REQ_CTX_new(BIO *wbio, BIO *rbio, int buf_size);
void OSSL_HTTP_REQ_CTX_free(OSSL_HTTP_REQ_CTX *rctx);
int OSSL_HTTP_REQ_CTX_set_request_line(OSSL_HTTP_REQ_CTX *rctx, int method_POST,
const char *server, const char *port,
const char *path);
int OSSL_HTTP_REQ_CTX_add1_header(OSSL_HTTP_REQ_CTX *rctx,
const char *name, const char *value);
int OSSL_HTTP_REQ_CTX_set_expected(OSSL_HTTP_REQ_CTX *rctx,
const char *content_type, int asn1,
int timeout, int keep_alive);
int OSSL_HTTP_REQ_CTX_set1_req(OSSL_HTTP_REQ_CTX *rctx, const char *content_type,
const ASN1_ITEM *it, ASN1_VALUE *req);
const ASN1_ITEM *it, const ASN1_VALUE *req);
int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx);
ASN1_VALUE *OSSL_HTTP_REQ_CTX_sendreq_d2i(OSSL_HTTP_REQ_CTX *rctx,
const ASN1_ITEM *it);
int OSSL_HTTP_REQ_CTX_nbio_d2i(OSSL_HTTP_REQ_CTX *rctx,
ASN1_VALUE **pval, const ASN1_ITEM *it);
BIO *OSSL_HTTP_REQ_CTX_exchange(OSSL_HTTP_REQ_CTX *rctx);
BIO *OSSL_HTTP_REQ_CTX_get0_mem_bio(const OSSL_HTTP_REQ_CTX *rctx);
size_t OSSL_HTTP_REQ_CTX_get_resp_len(const OSSL_HTTP_REQ_CTX *rctx);
void OSSL_HTTP_REQ_CTX_set_max_response_length(OSSL_HTTP_REQ_CTX *rctx,
unsigned long len);
int OSSL_HTTP_is_alive(const OSSL_HTTP_REQ_CTX *rctx);
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,
const STACK_OF(CONF_VALUE) *headers,
int maxline, unsigned long max_resp_len, int timeout,
const char *expected_ct, int expect_asn1);
ASN1_VALUE *OSSL_HTTP_get_asn1(const char *url,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
const ASN1_ITEM *rsp_it);
ASN1_VALUE *OSSL_HTTP_post_asn1(const char *server, const char *port,
const char *path, int use_ssl,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type,
const ASN1_VALUE *req, const ASN1_ITEM *req_it,
int maxline, unsigned long max_resp_len,
int timeout, const char *expected_ct,
const ASN1_ITEM *rsp_it);
BIO *OSSL_HTTP_transfer(const char *server, const char *port, const char *path,
int use_ssl, const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req_mem,
int maxline, unsigned long max_resp_len, int timeout,
const char *expected_ct, int expect_asn1,
char **redirection_url);
/* High-level HTTP API */
typedef BIO *(*OSSL_HTTP_bio_cb_t)(BIO *bio, void *arg, int connect, int detail);
OSSL_HTTP_REQ_CTX *OSSL_HTTP_open(const char *server, const char *port,
const char *proxy, const char *no_proxy,
int use_ssl, BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, int overall_timeout);
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);
int OSSL_HTTP_set_request(OSSL_HTTP_REQ_CTX *rctx, const char *path,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout, int keep_alive);
BIO *OSSL_HTTP_exchange(OSSL_HTTP_REQ_CTX *rctx, char **redirection_url);
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,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout);
BIO *OSSL_HTTP_transfer(OSSL_HTTP_REQ_CTX **prctx,
const char *server, const char *port,
const char *path, int use_ssl,
const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
size_t max_resp_len, int timeout, int keep_alive);
int OSSL_HTTP_close(OSSL_HTTP_REQ_CTX *rctx, int ok);
/* Auxiliary functions */
int OSSL_parse_url(const char *url, char **pscheme, char **puser, char **phost,
char **pport, int *pport_num,
char **ppath, char **pquery, char **pfrag);

View File

@ -29,6 +29,7 @@
# define HTTP_R_ERROR_RECEIVING 103
# define HTTP_R_ERROR_SENDING 102
# define HTTP_R_FAILED_READING_DATA 128
# define HTTP_R_HEADER_PARSE_ERROR 126
# define HTTP_R_INCONSISTENT_CONTENT_LENGTH 120
# define HTTP_R_INVALID_PORT_NUMBER 123
# define HTTP_R_INVALID_URL_PATH 125
@ -43,6 +44,7 @@
# 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_SERVER_CANCELED_CONNECTION 127
# define HTTP_R_SOCK_NOT_SUPPORTED 122
# define HTTP_R_STATUS_CODE_UNSUPPORTED 114
# define HTTP_R_TLS_NOT_ENABLED 107

View File

@ -170,34 +170,30 @@ typedef struct ocsp_service_locator_st OCSP_SERVICELOC;
DECLARE_ASN1_DUP_FUNCTION(OCSP_CERTID)
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, const char *path, OCSP_REQUEST *req);
OSSL_HTTP_REQ_CTX *OCSP_sendreq_new(BIO *io, const char *path,
const OCSP_REQUEST *req, int maxline);
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OSSL_HTTP_REQ_CTX *rctx);
const OCSP_REQUEST *req, int buf_size);
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, const char *path, OCSP_REQUEST *req);
# ifndef OPENSSL_NO_DEPRECATED_3_0
typedef OSSL_HTTP_REQ_CTX OCSP_REQ_CTX;
# define OCSP_REQ_CTX_new(io, maxline) \
OSSL_HTTP_REQ_CTX_new(io, io, maxline, 0, 0, NULL, 1)
# define OCSP_REQ_CTX_free(r) \
OSSL_HTTP_REQ_CTX_free(r)
# define OCSP_REQ_CTX_new(io, buf_size) \
OSSL_HTTP_REQ_CTX_new(io, io, buf_size)
# define OCSP_REQ_CTX_free OSSL_HTTP_REQ_CTX_free
# define OCSP_REQ_CTX_http(rctx, op, path) \
OSSL_HTTP_REQ_CTX_set_request_line(rctx, strcmp(op, "POST") == 0, \
NULL, NULL, path)
# define OCSP_REQ_CTX_add1_header(r, n, v) \
OSSL_HTTP_REQ_CTX_add1_header(r, n, v)
# define OCSP_REQ_CTX_add1_header OSSL_HTTP_REQ_CTX_add1_header
# define OCSP_REQ_CTX_i2d(r, it, req) \
OSSL_HTTP_REQ_CTX_set1_req(r, "application/ocsp-request", it, req)
# define OCSP_REQ_CTX_set1_req(r, req) \
OCSP_REQ_CTX_i2d(r, ASN1_ITEM_rptr(OCSP_REQUEST), (ASN1_VALUE *)(req))
# define OCSP_REQ_CTX_nbio(r) \
OSSL_HTTP_REQ_CTX_nbio(r)
# define OCSP_REQ_CTX_nbio_d2i(r, p, i) \
((*(p) = OSSL_HTTP_REQ_CTX_sendreq_d2i(r, i)) != NULL)
# define OCSP_REQ_CTX_get0_mem_bio(r) \
OSSL_HTTP_REQ_CTX_get0_mem_bio(r)
# define OCSP_set_max_response_length(r, l) \
OSSL_HTTP_REQ_CTX_set_max_response_length(r, l)
# define OCSP_REQ_CTX_nbio OSSL_HTTP_REQ_CTX_nbio
# define OCSP_REQ_CTX_nbio_d2i OSSL_HTTP_REQ_CTX_nbio_d2i
# define OCSP_sendreq_nbio(r, p) \
OSSL_HTTP_REQ_CTX_nbio_d2i(r, (ASN1_VALUE **)(p), \
ASN1_ITEM_rptr(OCSP_RESPONSE))
# define OCSP_REQ_CTX_get0_mem_bio OSSL_HTTP_REQ_CTX_get0_mem_bio
# define OCSP_set_max_response_length OSSL_HTTP_REQ_CTX_set_max_response_length
# endif
OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, const X509 *subject,

View File

@ -717,9 +717,8 @@ void cleanup_tests(void)
return;
}
DEFINE_SET_GET_ARG_FN(set, get, option, 16, int)
/* option == OSSL_CMP_OPT_IGNORE_KEYUSAGE */
DEFINE_SET_GET_BASE_TEST(OSSL_CMP_CTX, set, get, 0, option_16, int, -1, IS_0, \
DEFINE_SET_GET_ARG_FN(set, get, option, 35, int) /* OPT_IGNORE_KEYUSAGE */
DEFINE_SET_GET_BASE_TEST(OSSL_CMP_CTX, set, get, 0, option_35, int, -1, IS_0, \
1 /* true */, DROP)
DEFINE_SET_CB_TEST(log_cb)
@ -792,7 +791,7 @@ int setup_tests(void)
ADD_TEST(test_CTX_reinit);
/* various CMP options: */
ADD_TEST(test_CTX_set_get_option_16);
ADD_TEST(test_CTX_set_get_option_35);
/* CMP-specific callback for logging and outputting the error queue: */
ADD_TEST(test_CTX_set_get_log_cb);
/*

View File

@ -99,36 +99,38 @@ static int test_http_x509(int do_get)
X509 *rcert = NULL;
BIO *wbio = BIO_new(BIO_s_mem());
BIO *rbio = BIO_new(BIO_s_mem());
BIO *rsp, *req = ASN1_item_i2d_mem_bio(x509_it, (ASN1_VALUE *)x509);
STACK_OF(CONF_VALUE) *headers = NULL;
const char content_type[] = "application/x-x509-ca-cert";
int res = 0;
if (wbio == NULL || rbio == NULL)
if (wbio == NULL || rbio == NULL || req == NULL)
goto err;
BIO_set_callback_ex(wbio, http_bio_cb_ex);
BIO_set_callback_arg(wbio, (char *)rbio);
rpath = RPATH;
rcert = (X509 *)
(do_get ?
OSSL_HTTP_get_asn1("http://"SERVER":"PORT"/"RPATH,
NULL /* proxy */, NULL /* no_proxy */,
wbio, rbio, NULL /* bio_update_fn */, NULL,
headers, 0 /* maxline */,
0 /* max_resp_len */, 0 /* timeout */,
"application/x-x509-ca-cert", x509_it)
:
OSSL_HTTP_post_asn1(SERVER, PORT, RPATH, 0 /* use_ssl */,
NULL /* proxy */, NULL /* no_proxy */,
wbio, rbio, NULL /* bio_update_fn */, NULL,
headers, "application/x-x509-ca-cert",
(ASN1_VALUE *)x509, x509_it, 0 /* maxline */,
0 /* max_resp_len */, 0 /* timeout */,
"application/x-x509-ca-cert", x509_it)
);
rsp = do_get ?
OSSL_HTTP_get("http://"SERVER":"PORT"/"RPATH,
NULL /* proxy */, NULL /* no_proxy */,
wbio, rbio, NULL /* bio_fn */, NULL /* arg */,
0 /* buf_size */, headers, content_type,
1 /* expect_asn1 */,
HTTP_DEFAULT_MAX_RESP_LEN, 0 /* timeout */)
: OSSL_HTTP_transfer(NULL, NULL /* host */, NULL /* port */, RPATH,
0 /* use_ssl */,NULL /* proxy */, NULL /* no_pr */,
wbio, rbio, NULL /* bio_fn */, NULL /* arg */,
0 /* buf_size */, headers, content_type,
req, content_type, 1 /* expect_asn1 */,
HTTP_DEFAULT_MAX_RESP_LEN, 0 /* timeout */,
0 /* keep_alive */);
rcert = d2i_X509_bio(rsp, NULL);
BIO_free(rsp);
res = TEST_ptr(rcert) && TEST_int_eq(X509_cmp(x509, rcert), 0);
err:
X509_free(rcert);
BIO_free(req);
BIO_free(wbio);
BIO_free(rbio);
sk_CONF_VALUE_pop_free(headers, X509V3_conf_free);

View File

@ -614,7 +614,7 @@ UI_get0_result_string 629 3_0_0 EXIST::FUNCTION:
TS_RESP_CTX_add_policy 630 3_0_0 EXIST::FUNCTION:TS
X509_REQ_dup 631 3_0_0 EXIST::FUNCTION:
d2i_DSA_PUBKEY_fp 633 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0,DSA,STDIO
OSSL_HTTP_REQ_CTX_sendreq_d2i 634 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_REQ_CTX_exchange 634 3_0_0 EXIST::FUNCTION:
d2i_X509_REQ_fp 635 3_0_0 EXIST::FUNCTION:STDIO
DH_OpenSSL 636 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0,DH
BN_get_rfc3526_prime_8192 637 3_0_0 EXIST::FUNCTION:
@ -3612,7 +3612,7 @@ EVP_CIPHER_CTX_encrypting 3694 3_0_0 EXIST::FUNCTION:
EC_KEY_can_sign 3695 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0,EC
PEM_write_bio_RSAPublicKey 3696 3_0_0 EXIST::FUNCTION:DEPRECATEDIN_3_0
X509_CRL_set1_lastUpdate 3697 3_0_0 EXIST::FUNCTION:
OCSP_sendreq_nbio 3698 3_0_0 EXIST::FUNCTION:OCSP
OSSL_HTTP_REQ_CTX_nbio_d2i 3698 3_0_0 EXIST::FUNCTION:
PKCS8_encrypt 3699 3_0_0 EXIST::FUNCTION:
i2d_PKCS7_fp 3700 3_0_0 EXIST::FUNCTION:STDIO
i2d_X509_REQ 3701 3_0_0 EXIST::FUNCTION:
@ -4882,11 +4882,16 @@ BIO_socket_wait ? 3_0_0 EXIST::FUNCTION:SOCK
BIO_wait ? 3_0_0 EXIST::FUNCTION:
BIO_do_connect_retry ? 3_0_0 EXIST::FUNCTION:
OSSL_parse_url ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_get ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_get_asn1 ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_post_asn1 ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_transfer ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_REQ_CTX_get_resp_len ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_REQ_CTX_set_expected ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_is_alive ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_open ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_proxy_connect ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_set_request ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_exchange ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_get ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_transfer ? 3_0_0 EXIST::FUNCTION:
OSSL_HTTP_close ? 3_0_0 EXIST::FUNCTION:
ASN1_item_i2d_mem_bio ? 3_0_0 EXIST::FUNCTION:
ERR_add_error_txt ? 3_0_0 EXIST::FUNCTION:
ERR_add_error_mem_bio ? 3_0_0 EXIST::FUNCTION:

View File

@ -781,7 +781,6 @@ OCSP_REQ_CTX_get0_mem_bio(3)
OCSP_REQ_CTX_http(3)
OCSP_REQ_CTX_new(3)
OCSP_REQ_CTX_nbio(3)
OCSP_REQ_CTX_nbio_d2i(3)
OCSP_REQUEST_add1_ext_i2d(3)
OCSP_REQUEST_add_ext(3)
OCSP_REQUEST_delete_ext(3)

View File

@ -339,8 +339,9 @@ OCSP_REQ_CTX datatype deprecated 3.0.0
OCSP_REQ_CTX_add1_header define deprecated 3.0.0
OCSP_REQ_CTX_free define deprecated 3.0.0
OCSP_REQ_CTX_i2d define deprecated 3.0.0
OCSP_set_max_response_length define deprecated 3.0.0
OCSP_REQ_CTX_set1_req define deprecated 3.0.0
OCSP_sendreq_nbio define deprecated 3.0.0
OCSP_set_max_response_length define deprecated 3.0.0
OPENSSL_FILE define
OPENSSL_FUNC define
OPENSSL_LINE define