[openssl] master update
dev at ddvo.net
dev at ddvo.net
Sat May 9 14:58:23 UTC 2020
The branch master has been updated
via 582311d7b469b4f57a29e9c3965c4d1eb4b477d4 (commit)
via d8c78e5f4ac5c882ca878b9e9038896d5786aafa (commit)
via 9253f8346acf065d8d52eb03aa87e2c7eb4f7cce (commit)
via 045229cfe88aba44f8b67e7306281f6fbf516625 (commit)
from 8c30dfee3ea038b71f339f193331ed6ac11e3055 (commit)
- Log -----------------------------------------------------------------
commit 582311d7b469b4f57a29e9c3965c4d1eb4b477d4
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date: Mon May 4 20:29:25 2020 +0200
Extract HTTP server code from apps/ocsp.c to apps/lib/http_server.c
Also adds apps/include/http_server.h.
This is used so far by apps/ocsp.c and is going to be used for apps/cmp.c
and will be helpful also for any future app acting as HTTP server.
Reviewed-by: Matt Caswell <matt at openssl.org>
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11736)
commit d8c78e5f4ac5c882ca878b9e9038896d5786aafa
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date: Mon May 4 20:21:34 2020 +0200
Fix bio_wait() in crypto/bio/bio_lib.c in case OPENSSL_NO_SOCK
Reviewed-by: Matt Caswell <matt at openssl.org>
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11736)
commit 9253f8346acf065d8d52eb03aa87e2c7eb4f7cce
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date: Mon May 4 19:54:43 2020 +0200
Constify 'req' parameter of OSSL_HTTP_post_asn1()
Reviewed-by: Matt Caswell <matt at openssl.org>
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11736)
commit 045229cfe88aba44f8b67e7306281f6fbf516625
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date: Mon May 4 19:53:09 2020 +0200
Fix bug in OSSL_CMP_SRV_process_request() on transaction renewal
Reviewed-by: Matt Caswell <matt at openssl.org>
Reviewed-by: Viktor Dukhovni <viktor at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11736)
-----------------------------------------------------------------------
Summary of changes:
apps/include/http_server.h | 102 +++++++++
apps/lib/build.info | 2 +-
apps/lib/http_server.c | 394 +++++++++++++++++++++++++++++++++++
apps/ocsp.c | 447 ++++------------------------------------
crypto/bio/bio_lib.c | 2 +
crypto/cmp/cmp_http.c | 4 +-
crypto/cmp/cmp_server.c | 10 +-
crypto/http/http_client.c | 4 +-
crypto/http/http_local.h | 2 +-
doc/man3/OSSL_HTTP_transfer.pod | 2 +-
include/openssl/http.h | 2 +-
11 files changed, 551 insertions(+), 420 deletions(-)
create mode 100644 apps/include/http_server.h
create mode 100644 apps/lib/http_server.c
diff --git a/apps/include/http_server.h b/apps/include/http_server.h
new file mode 100644
index 0000000000..8c65521339
--- /dev/null
+++ b/apps/include/http_server.h
@@ -0,0 +1,102 @@
+/*
+ * 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_HTTP_SERVER_H
+# define OSSL_HTTP_SERVER_H
+
+# include "apps.h"
+
+# ifndef HAVE_FORK
+# if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS)
+# define HAVE_FORK 0
+# else
+# define HAVE_FORK 1
+# endif
+# endif
+
+# if HAVE_FORK
+# undef NO_FORK
+# else
+# define NO_FORK
+# endif
+
+# if !defined(NO_FORK) && !defined(OPENSSL_NO_SOCK) \
+ && !defined(OPENSSL_NO_POSIX_IO)
+# define HTTP_DAEMON
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <syslog.h>
+# include <signal.h>
+# define MAXERRLEN 1000 /* limit error text sent to syslog to 1000 bytes */
+# else
+# undef LOG_INFO
+# undef LOG_WARNING
+# undef LOG_ERR
+# define LOG_INFO 0
+# define LOG_WARNING 1
+# define LOG_ERR 2
+# endif
+
+/*-
+ * Log a message to syslog if multi-threaded HTTP_DAEMON, else to bio_err
+ * prog: the name of the current app
+ * level: the severity of the message, e.g., LOG_ERR
+ * fmt: message with potential extra parameters like with printf()
+ * returns nothing
+ */
+void log_message(const char *prog, int level, const char *fmt, ...);
+
+# ifndef OPENSSL_NO_SOCK
+/*-
+ * Initialize an HTTP server by setting up its listening BIO
+ * prog: the name of the current app
+ * port: the port to listen on
+ * returns a BIO for accepting requests, NULL on error
+ */
+BIO *http_server_init_bio(const char *prog, const char *port);
+/*-
+ * Accept an ASN.1-formatted HTTP request
+ * it: the expected request ASN.1 type
+ * preq: pointer to variable where to place the parsed request
+ * pcbio: pointer to variable where to place the BIO for sending the response to
+ * acbio: the listening bio (typically as returned by http_server_init_bio())
+ * prog: the name of the current app
+ * accept_get: wheter to accept GET requests (in addition to POST requests)
+ * timeout: connection timeout (in seconds), or 0 for none/infinite
+ * returns 0 in case caller should retry, then *preq == *pcbio == NULL
+ * returns -1 on fatal error; also in this case *preq == *pcbio == NULL
+ * returns 1 otherwise. In this case it is guaranteed that *pcbio != NULL
+ * while *preq == NULL if and only if request is invalid
+ */
+int http_server_get_asn1_req(const ASN1_ITEM *it, ASN1_VALUE **preq,
+ BIO **pcbio, BIO *acbio,
+ const char *prog, int accept_get, int timeout);
+/*-
+ * Send an ASN.1-formatted HTTP response
+ * cbio: destination BIO (typically as returned by http_server_get_asn1_req())
+ * note: cbio should not do an encoding that changes the output length
+ * content_type: string identifying the type of the response
+ * it: the response ASN.1 type
+ * valit: the response ASN.1 type
+ * resp: the response to send
+ * returns 1 on success, 0 on failure
+ */
+int http_server_send_asn1_resp(BIO *cbio, const char *content_type,
+ const ASN1_ITEM *it, const ASN1_VALUE *resp);
+# endif
+
+# ifdef HTTP_DAEMON
+extern int multi;
+extern int acfd;
+
+void socket_timeout(int signum);
+void spawn_loop(const char *prog);
+# endif
+
+#endif
diff --git a/apps/lib/build.info b/apps/lib/build.info
index 129ffce933..22db095c51 100644
--- a/apps/lib/build.info
+++ b/apps/lib/build.info
@@ -9,7 +9,7 @@ ENDIF
# Source for libapps
$LIBAPPSSRC=apps.c apps_ui.c opt.c fmt.c s_cb.c s_socket.c app_rand.c \
- columns.c app_params.c names.c app_provider.c app_x509.c
+ columns.c app_params.c names.c app_provider.c app_x509.c http_server.c
IF[{- !$disabled{apps} -}]
LIBS{noinst}=../libapps.a
diff --git a/apps/lib/http_server.c b/apps/lib/http_server.c
new file mode 100644
index 0000000000..6db11f4150
--- /dev/null
+++ b/apps/lib/http_server.c
@@ -0,0 +1,394 @@
+/*
+ * 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* Very basic HTTP server */
+
+#if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS)
+/*
+ * On VMS, you need to define this to get the declaration of fileno(). The
+ * value 2 is to make sure no function defined in POSIX-2 is left undefined.
+ */
+# define _POSIX_C_SOURCE 2
+#endif
+
+#include <ctype.h>
+#include "http_server.h"
+#include "internal/sockets.h"
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+int multi = 0; /* run multiple responder processes */
+
+#ifdef HTTP_DAEMON
+int acfd = (int) INVALID_SOCKET;
+#endif
+
+#ifdef HTTP_DAEMON
+static int print_syslog(const char *str, size_t len, void *levPtr)
+{
+ int level = *(int *)levPtr;
+ int ilen = len > MAXERRLEN ? MAXERRLEN : len;
+
+ syslog(level, "%.*s", ilen, str);
+
+ return ilen;
+}
+#endif
+
+void log_message(const char *prog, int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+#ifdef HTTP_DAEMON
+ if (multi) {
+ char buf[1024];
+
+ if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0)
+ syslog(level, "%s", buf);
+ if (level >= LOG_ERR)
+ ERR_print_errors_cb(print_syslog, &level);
+ }
+#endif
+ if (!multi) {
+ BIO_printf(bio_err, "%s: ", prog);
+ BIO_vprintf(bio_err, fmt, ap);
+ BIO_printf(bio_err, "\n");
+ }
+ va_end(ap);
+}
+
+#ifdef HTTP_DAEMON
+void socket_timeout(int signum)
+{
+ if (acfd != (int)INVALID_SOCKET)
+ (void)shutdown(acfd, SHUT_RD);
+}
+
+static void killall(int ret, pid_t *kidpids)
+{
+ int i;
+
+ for (i = 0; i < multi; ++i)
+ if (kidpids[i] != 0)
+ (void)kill(kidpids[i], SIGTERM);
+ OPENSSL_free(kidpids);
+ sleep(1);
+ exit(ret);
+}
+
+static int termsig = 0;
+
+static void noteterm(int sig)
+{
+ termsig = sig;
+}
+
+/*
+ * Loop spawning up to `multi` child processes, only child processes return
+ * from this function. The parent process loops until receiving a termination
+ * signal, kills extant children and exits without returning.
+ */
+void spawn_loop(const char *prog)
+{
+ pid_t *kidpids = NULL;
+ int status;
+ int procs = 0;
+ int i;
+
+ openlog(prog, LOG_PID, LOG_DAEMON);
+
+ if (setpgid(0, 0)) {
+ syslog(LOG_ERR, "fatal: error detaching from parent process group: %s",
+ strerror(errno));
+ exit(1);
+ }
+ kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array");
+ for (i = 0; i < multi; ++i)
+ kidpids[i] = 0;
+
+ signal(SIGINT, noteterm);
+ signal(SIGTERM, noteterm);
+
+ while (termsig == 0) {
+ pid_t fpid;
+
+ /*
+ * Wait for a child to replace when we're at the limit.
+ * Slow down if a child exited abnormally or waitpid() < 0
+ */
+ while (termsig == 0 && procs >= multi) {
+ if ((fpid = waitpid(-1, &status, 0)) > 0) {
+ for (i = 0; i < procs; ++i) {
+ if (kidpids[i] == fpid) {
+ kidpids[i] = 0;
+ --procs;
+ break;
+ }
+ }
+ if (i >= multi) {
+ syslog(LOG_ERR, "fatal: internal error: "
+ "no matching child slot for pid: %ld",
+ (long) fpid);
+ killall(1, kidpids);
+ }
+ if (status != 0) {
+ if (WIFEXITED(status))
+ syslog(LOG_WARNING, "child process: %ld, exit status: %d",
+ (long)fpid, WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ syslog(LOG_WARNING, "child process: %ld, term signal %d%s",
+ (long)fpid, WTERMSIG(status),
+# ifdef WCOREDUMP
+ WCOREDUMP(status) ? " (core dumped)" :
+# endif
+ "");
+ sleep(1);
+ }
+ break;
+ } else if (errno != EINTR) {
+ syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno));
+ killall(1, kidpids);
+ }
+ }
+ if (termsig)
+ break;
+
+ switch (fpid = fork()) {
+ case -1: /* error */
+ /* System critically low on memory, pause and try again later */
+ sleep(30);
+ break;
+ case 0: /* child */
+ OPENSSL_free(kidpids);
+ signal(SIGINT, SIG_DFL);
+ signal(SIGTERM, SIG_DFL);
+ if (termsig)
+ _exit(0);
+ if (RAND_poll() <= 0) {
+ syslog(LOG_ERR, "fatal: RAND_poll() failed");
+ _exit(1);
+ }
+ return;
+ default: /* parent */
+ for (i = 0; i < multi; ++i) {
+ if (kidpids[i] == 0) {
+ kidpids[i] = fpid;
+ procs++;
+ break;
+ }
+ }
+ if (i >= multi) {
+ syslog(LOG_ERR, "fatal: internal error: no free child slots");
+ killall(1, kidpids);
+ }
+ break;
+ }
+ }
+
+ /* The loop above can only break on termsig */
+ syslog(LOG_INFO, "terminating on signal: %d", termsig);
+ killall(0, kidpids);
+}
+#endif
+
+#ifndef OPENSSL_NO_SOCK
+BIO *http_server_init_bio(const char *prog, const char *port)
+{
+ BIO *acbio = NULL, *bufbio;
+
+ bufbio = BIO_new(BIO_f_buffer());
+ if (bufbio == NULL)
+ goto err;
+ acbio = BIO_new(BIO_s_accept());
+ if (acbio == NULL
+ || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0
+ || BIO_set_accept_port(acbio, port) < 0) {
+ log_message(prog, LOG_ERR, "Error setting up accept BIO");
+ goto err;
+ }
+
+ BIO_set_accept_bios(acbio, bufbio);
+ bufbio = NULL;
+ if (BIO_do_accept(acbio) <= 0) {
+ log_message(prog, LOG_ERR, "Error starting accept");
+ goto err;
+ }
+
+ return acbio;
+
+ err:
+ BIO_free_all(acbio);
+ BIO_free(bufbio);
+ return NULL;
+}
+
+/*
+ * Decode %xx URL-decoding in-place. Ignores malformed sequences.
+ */
+static int urldecode(char *p)
+{
+ unsigned char *out = (unsigned char *)p;
+ unsigned char *save = out;
+
+ for (; *p; p++) {
+ if (*p != '%') {
+ *out++ = *p;
+ } else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) {
+ /* Don't check, can't fail because of ixdigit() call. */
+ *out++ = (OPENSSL_hexchar2int(p[1]) << 4)
+ | OPENSSL_hexchar2int(p[2]);
+ p += 2;
+ } else {
+ return -1;
+ }
+ }
+ *out = '\0';
+ return (int)(out - save);
+}
+
+int http_server_get_asn1_req(const ASN1_ITEM *it, ASN1_VALUE **preq,
+ BIO **pcbio, BIO *acbio,
+ const char *prog, int accept_get, int timeout)
+{
+ BIO *cbio = NULL, *getbio = NULL, *b64 = NULL;
+ int len;
+ char reqbuf[2048], inbuf[2048];
+ char *url, *end;
+ ASN1_VALUE *req;
+ int ret = 1;
+
+ *preq = NULL;
+ *pcbio = NULL;
+
+ /* Connection loss before accept() is routine, ignore silently */
+ if (BIO_do_accept(acbio) <= 0)
+ return 0;
+
+ cbio = BIO_pop(acbio);
+ *pcbio = cbio;
+ if (cbio == NULL) {
+ ret = -1;
+ goto out;
+ }
+
+# ifdef HTTP_DAEMON
+ if (timeout > 0) {
+ (void)BIO_get_fd(cbio, &acfd);
+ alarm(timeout);
+ }
+# endif
+
+ /* Read the request line. */
+ len = BIO_gets(cbio, reqbuf, sizeof(reqbuf));
+ if (len <= 0)
+ goto out;
+
+ if (accept_get && strncmp(reqbuf, "GET ", 4) == 0) {
+ /* Expecting GET {sp} /URL {sp} HTTP/1.x */
+ for (url = reqbuf + 4; *url == ' '; ++url)
+ continue;
+ if (*url != '/') {
+ log_message(prog, LOG_INFO,
+ "Invalid GET -- URL does not begin with '/': %s", url);
+ goto out;
+ }
+ url++;
+
+ /* Splice off the HTTP version identifier. */
+ for (end = url; *end != '\0'; end++)
+ if (*end == ' ')
+ break;
+ if (strncmp(end, " HTTP/1.", 7) != 0) {
+ log_message(prog, LOG_INFO,
+ "Invalid GET -- bad HTTP/version string: %s", end + 1);
+ goto out;
+ }
+ *end = '\0';
+
+ /*-
+ * Skip "GET / HTTP..." requests often used by load-balancers.
+ * 'url' was incremented above to point to the first byte *after*
+ * the leading slash, so in case 'GET / ' it is now an empty string.
+ */
+ if (url[0] == '\0')
+ goto out;
+
+ len = urldecode(url);
+ if (len <= 0) {
+ log_message(prog, LOG_INFO,
+ "Invalid GET request -- bad URL encoding: %s", url);
+ goto out;
+ }
+ if ((getbio = BIO_new_mem_buf(url, len)) == NULL
+ || (b64 = BIO_new(BIO_f_base64())) == NULL) {
+ log_message(prog, LOG_ERR,
+ "Could not allocate base64 bio with size = %d", len);
+ BIO_free_all(cbio);
+ *pcbio = NULL;
+ ret = -1;
+ goto out;
+ }
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ getbio = BIO_push(b64, getbio);
+ } else if (strncmp(reqbuf, "POST ", 5) != 0) {
+ log_message(prog, LOG_INFO,
+ "HTTP request does not start with GET/POST: %s", reqbuf);
+ /* TODO provide better diagnosis in case client tries TLS */
+ goto out;
+ }
+
+ /* Read and skip past the headers. */
+ for (;;) {
+ len = BIO_gets(cbio, inbuf, sizeof(inbuf));
+ if (len <= 0) {
+ log_message(prog, LOG_ERR,
+ "Error skipping remaining HTTP headers");
+ goto out;
+ }
+ if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
+ break;
+ }
+
+# ifdef HTTP_DAEMON
+ /* Clear alarm before we close the client socket */
+ alarm(0);
+ timeout = 0;
+# endif
+
+ /* Try to read and parse request */
+ req = ASN1_item_d2i_bio(it, getbio != NULL ? getbio : cbio, NULL);
+ if (req == NULL)
+ log_message(prog, LOG_ERR, "Error parsing request");
+
+ *preq = req;
+
+ out:
+ BIO_free_all(getbio);
+# ifdef HTTP_DAEMON
+ if (timeout > 0)
+ alarm(0);
+ acfd = (int)INVALID_SOCKET;
+# endif
+ return ret;
+}
+
+/* assumes that cbio does not do an encoding that changes the output length */
+int http_server_send_asn1_resp(BIO *cbio, const char *content_type,
+ const ASN1_ITEM *it, const ASN1_VALUE *resp)
+{
+ int ret = BIO_printf(cbio, "HTTP/1.0 200 OK\r\nContent-type: %s\r\n"
+ "Content-Length: %d\r\n\r\n", content_type,
+ ASN1_item_i2d(resp, NULL, it)) > 0
+ && ASN1_item_i2d_bio(it, cbio, resp) > 0;
+
+ (void)BIO_flush(cbio);
+ return ret;
+}
+#endif
diff --git a/apps/ocsp.c b/apps/ocsp.c
index d85892202a..5f9c5cf326 100644
--- a/apps/ocsp.c
+++ b/apps/ocsp.c
@@ -22,6 +22,7 @@
/* Needs to be included before the openssl headers */
#include "apps.h"
+#include "http_server.h"
#include "progs.h"
#include "internal/sockets.h"
#include <openssl/e_os2.h>
@@ -31,44 +32,12 @@
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/x509v3.h>
-#include <openssl/rand.h>
DEFINE_STACK_OF(OCSP_CERTID)
DEFINE_STACK_OF(CONF_VALUE)
DEFINE_STACK_OF(X509)
DEFINE_STACK_OF_STRING()
-#ifndef HAVE_FORK
-# if defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_WINDOWS)
-# define HAVE_FORK 0
-# else
-# define HAVE_FORK 1
-# endif
-#endif
-
-#if HAVE_FORK
-# undef NO_FORK
-#else
-# define NO_FORK
-#endif
-
-#if !defined(NO_FORK) && !defined(OPENSSL_NO_SOCK) \
- && !defined(OPENSSL_NO_POSIX_IO)
-# define OCSP_DAEMON
-# include <sys/types.h>
-# include <sys/wait.h>
-# include <syslog.h>
-# include <signal.h>
-# define MAXERRLEN 1000 /* limit error text sent to syslog to 1000 bytes */
-#else
-# undef LOG_INFO
-# undef LOG_WARNING
-# undef LOG_ERR
-# define LOG_INFO 0
-# define LOG_WARNING 1
-# define LOG_ERR 2
-#endif
-
#if defined(OPENSSL_SYS_VXWORKS)
/* not supported */
int setpgid(pid_t pid, pid_t pgid)
@@ -105,19 +74,13 @@ static void make_ocsp_response(BIO *err, OCSP_RESPONSE **resp, OCSP_REQUEST *req
const EVP_MD *resp_md);
static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser);
-static BIO *init_responder(const char *port);
-static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, int timeout);
-static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp);
-static void log_message(int level, const char *fmt, ...);
+static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
+ int timeout);
+static int send_ocsp_response(BIO *cbio, const OCSP_RESPONSE *resp);
static char *prog;
-static int multi = 0;
-#ifdef OCSP_DAEMON
-static int acfd = (int) INVALID_SOCKET;
+#ifdef HTTP_DAEMON
static int index_changed(CA_DB *);
-static void spawn_loop(void);
-static int print_syslog(const char *str, size_t len, void *levPtr);
-static void socket_timeout(int signum);
#endif
typedef enum OPTION_choice {
@@ -162,7 +125,7 @@ const OPTIONS ocsp_options[] = {
"Connection timeout (in seconds) to the OCSP responder"},
{"resp_no_certs", OPT_RESP_NO_CERTS, '-',
"Don't include any certificates in response"},
-#ifdef OCSP_DAEMON
+#ifdef HTTP_DAEMON
{"multi", OPT_MULTI, 'p', "run multiple responder processes"},
#endif
{"no_certs", OPT_NO_CERTS, '-',
@@ -540,7 +503,7 @@ int ocsp_main(int argc, char **argv)
trailing_md = 1;
break;
case OPT_MULTI:
-#ifdef OCSP_DAEMON
+#ifdef HTTP_DAEMON
multi = atoi(opt_arg());
#endif
break;
@@ -584,9 +547,14 @@ int ocsp_main(int argc, char **argv)
}
if (req == NULL && port != NULL) {
- acbio = init_responder(port);
+#ifndef OPENSSL_NO_SOCK
+ acbio = http_server_init_bio(prog, port);
if (acbio == NULL)
goto end;
+#else
+ BIO_printf(bio_err, "Cannot act as server - sockets not supported\n");
+ goto end;
+#endif
}
if (rsignfile != NULL) {
@@ -630,20 +598,20 @@ int ocsp_main(int argc, char **argv)
}
}
-#ifdef OCSP_DAEMON
+#ifdef HTTP_DAEMON
if (multi && acbio != NULL)
- spawn_loop();
+ spawn_loop(prog);
if (acbio != NULL && req_timeout > 0)
signal(SIGALRM, socket_timeout);
#endif
if (acbio != NULL)
- log_message(LOG_INFO, "waiting for OCSP client connections...");
+ log_message(prog, LOG_INFO, "waiting for OCSP client connections...");
redo_accept:
if (acbio != NULL) {
-#ifdef OCSP_DAEMON
+#ifdef HTTP_DAEMON
if (index_changed(rdb)) {
CA_DB *newrdb = load_index(ridx_filename, NULL);
@@ -652,7 +620,7 @@ redo_accept:
rdb = newrdb;
} else {
free_index(newrdb);
- log_message(LOG_ERR, "error reloading updated index: %s",
+ log_message(prog, LOG_ERR, "error reloading updated index: %s",
ridx_filename);
}
}
@@ -663,9 +631,8 @@ redo_accept:
goto redo_accept;
if (req == NULL) {
- resp =
- OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST,
- NULL);
+ resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST,
+ NULL);
send_ocsp_response(cbio, resp);
goto done_resp;
}
@@ -733,7 +700,7 @@ redo_accept:
goto end;
#else
BIO_printf(bio_err,
- "Error creating connect BIO - sockets not supported.\n");
+ "Error creating connect BIO - sockets not supported\n");
goto end;
#endif
} else if (respin != NULL) {
@@ -873,41 +840,7 @@ redo_accept:
return ret;
}
-static void
-log_message(int level, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
-#ifdef OCSP_DAEMON
- if (multi) {
- char buf[1024];
- if (vsnprintf(buf, sizeof(buf), fmt, ap) > 0) {
- syslog(level, "%s", buf);
- }
- if (level >= LOG_ERR)
- ERR_print_errors_cb(print_syslog, &level);
- }
-#endif
- if (!multi) {
- BIO_printf(bio_err, "%s: ", prog);
- BIO_vprintf(bio_err, fmt, ap);
- BIO_printf(bio_err, "\n");
- }
- va_end(ap);
-}
-
-#ifdef OCSP_DAEMON
-
-static int print_syslog(const char *str, size_t len, void *levPtr)
-{
- int level = *(int *)levPtr;
- int ilen = (len > MAXERRLEN) ? MAXERRLEN : len;
-
- syslog(level, "%.*s", ilen, str);
-
- return ilen;
-}
+#ifdef HTTP_DAEMON
static int index_changed(CA_DB *rdb)
{
@@ -925,131 +858,6 @@ static int index_changed(CA_DB *rdb)
return 0;
}
-static void killall(int ret, pid_t *kidpids)
-{
- int i;
-
- for (i = 0; i < multi; ++i)
- if (kidpids[i] != 0)
- (void)kill(kidpids[i], SIGTERM);
- OPENSSL_free(kidpids);
- sleep(1);
- exit(ret);
-}
-
-static int termsig = 0;
-
-static void noteterm (int sig)
-{
- termsig = sig;
-}
-
-/*
- * Loop spawning up to `multi` child processes, only child processes return
- * from this function. The parent process loops until receiving a termination
- * signal, kills extant children and exits without returning.
- */
-static void spawn_loop(void)
-{
- pid_t *kidpids = NULL;
- int status;
- int procs = 0;
- int i;
-
- openlog(prog, LOG_PID, LOG_DAEMON);
-
- if (setpgid(0, 0)) {
- syslog(LOG_ERR, "fatal: error detaching from parent process group: %s",
- strerror(errno));
- exit(1);
- }
- kidpids = app_malloc(multi * sizeof(*kidpids), "child PID array");
- for (i = 0; i < multi; ++i)
- kidpids[i] = 0;
-
- signal(SIGINT, noteterm);
- signal(SIGTERM, noteterm);
-
- while (termsig == 0) {
- pid_t fpid;
-
- /*
- * Wait for a child to replace when we're at the limit.
- * Slow down if a child exited abnormally or waitpid() < 0
- */
- while (termsig == 0 && procs >= multi) {
- if ((fpid = waitpid(-1, &status, 0)) > 0) {
- for (i = 0; i < procs; ++i) {
- if (kidpids[i] == fpid) {
- kidpids[i] = 0;
- --procs;
- break;
- }
- }
- if (i >= multi) {
- syslog(LOG_ERR, "fatal: internal error: "
- "no matching child slot for pid: %ld",
- (long) fpid);
- killall(1, kidpids);
- }
- if (status != 0) {
- if (WIFEXITED(status))
- syslog(LOG_WARNING, "child process: %ld, exit status: %d",
- (long)fpid, WEXITSTATUS(status));
- else if (WIFSIGNALED(status))
- syslog(LOG_WARNING, "child process: %ld, term signal %d%s",
- (long)fpid, WTERMSIG(status),
-#ifdef WCOREDUMP
- WCOREDUMP(status) ? " (core dumped)" :
-#endif
- "");
- sleep(1);
- }
- break;
- } else if (errno != EINTR) {
- syslog(LOG_ERR, "fatal: waitpid(): %s", strerror(errno));
- killall(1, kidpids);
- }
- }
- if (termsig)
- break;
-
- switch(fpid = fork()) {
- case -1: /* error */
- /* System critically low on memory, pause and try again later */
- sleep(30);
- break;
- case 0: /* child */
- OPENSSL_free(kidpids);
- signal(SIGINT, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- if (termsig)
- _exit(0);
- if (RAND_poll() <= 0) {
- syslog(LOG_ERR, "fatal: RAND_poll() failed");
- _exit(1);
- }
- return;
- default: /* parent */
- for (i = 0; i < multi; ++i) {
- if (kidpids[i] == 0) {
- kidpids[i] = fpid;
- procs++;
- break;
- }
- }
- if (i >= multi) {
- syslog(LOG_ERR, "fatal: internal error: no free child slots");
- killall(1, kidpids);
- }
- break;
- }
- }
-
- /* The loop above can only break on termsig */
- syslog(LOG_INFO, "terminating on signal: %d", termsig);
- killall(0, kidpids);
-}
#endif
static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert,
@@ -1336,209 +1144,32 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser)
return rrow;
}
-/* Quick and dirty OCSP server: read in and parse input request */
-
-static BIO *init_responder(const char *port)
-{
-#ifdef OPENSSL_NO_SOCK
- BIO_printf(bio_err,
- "Error setting up accept BIO - sockets not supported.\n");
- return NULL;
-#else
- BIO *acbio = NULL, *bufbio = NULL;
-
- bufbio = BIO_new(BIO_f_buffer());
- if (bufbio == NULL)
- goto err;
- acbio = BIO_new(BIO_s_accept());
- if (acbio == NULL
- || BIO_set_bind_mode(acbio, BIO_BIND_REUSEADDR) < 0
- || BIO_set_accept_port(acbio, port) < 0) {
- log_message(LOG_ERR, "Error setting up accept BIO");
- goto err;
- }
-
- BIO_set_accept_bios(acbio, bufbio);
- bufbio = NULL;
- if (BIO_do_accept(acbio) <= 0) {
- log_message(LOG_ERR, "Error starting accept");
- goto err;
- }
-
- return acbio;
-
- err:
- BIO_free_all(acbio);
- BIO_free(bufbio);
- return NULL;
-#endif
-}
-
-#ifndef OPENSSL_NO_SOCK
-/*
- * Decode %xx URL-decoding in-place. Ignores mal-formed sequences.
- */
-static int urldecode(char *p)
-{
- unsigned char *out = (unsigned char *)p;
- unsigned char *save = out;
-
- for (; *p; p++) {
- if (*p != '%')
- *out++ = *p;
- else if (isxdigit(_UC(p[1])) && isxdigit(_UC(p[2]))) {
- /* Don't check, can't fail because of ixdigit() call. */
- *out++ = (OPENSSL_hexchar2int(p[1]) << 4)
- | OPENSSL_hexchar2int(p[2]);
- p += 2;
- }
- else
- return -1;
- }
- *out = '\0';
- return (int)(out - save);
-}
-#endif
-
-#ifdef OCSP_DAEMON
-static void socket_timeout(int signum)
-{
- if (acfd != (int)INVALID_SOCKET)
- (void)shutdown(acfd, SHUT_RD);
-}
-#endif
-
static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio,
int timeout)
{
-#ifdef OPENSSL_NO_SOCK
- return 0;
+#ifndef OPENSSL_NO_SOCK
+ return http_server_get_asn1_req(ASN1_ITEM_rptr(OCSP_RESPONSE),
+ (ASN1_VALUE **)preq, pcbio, acbio,
+ prog, 1 /* accept_get */, timeout);
#else
- int len;
- OCSP_REQUEST *req = NULL;
- char inbuf[2048], reqbuf[2048];
- char *p, *q;
- BIO *cbio = NULL, *getbio = NULL, *b64 = NULL;
- const char *client;
-
+ BIO_printf(bio_err,
+ "Error getting OCSP request - sockets not supported\n");
*preq = NULL;
-
- /* Connection loss before accept() is routine, ignore silently */
- if (BIO_do_accept(acbio) <= 0)
- return 0;
-
- cbio = BIO_pop(acbio);
- *pcbio = cbio;
- client = BIO_get_peer_name(cbio);
-
-# ifdef OCSP_DAEMON
- if (timeout > 0) {
- (void) BIO_get_fd(cbio, &acfd);
- alarm(timeout);
- }
-# endif
-
- /* Read the request line. */
- len = BIO_gets(cbio, reqbuf, sizeof(reqbuf));
- if (len <= 0)
- goto out;
-
- if (strncmp(reqbuf, "GET ", 4) == 0) {
- /* Expecting GET {sp} /URL {sp} HTTP/1.x */
- for (p = reqbuf + 4; *p == ' '; ++p)
- continue;
- if (*p != '/') {
- log_message(LOG_INFO, "Invalid request -- bad URL: %s", client);
- goto out;
- }
- p++;
-
- /* Splice off the HTTP version identifier. */
- for (q = p; *q; q++)
- if (*q == ' ')
- break;
- if (strncmp(q, " HTTP/1.", 8) != 0) {
- log_message(LOG_INFO,
- "Invalid request -- bad HTTP version: %s", client);
- goto out;
- }
- *q = '\0';
-
- /*
- * Skip "GET / HTTP..." requests often used by load-balancers. Note:
- * 'p' was incremented above to point to the first byte *after* the
- * leading slash, so with 'GET / ' it is now an empty string.
- */
- if (p[0] == '\0')
- goto out;
-
- len = urldecode(p);
- if (len <= 0) {
- log_message(LOG_INFO,
- "Invalid request -- bad URL encoding: %s", client);
- goto out;
- }
- if ((getbio = BIO_new_mem_buf(p, len)) == NULL
- || (b64 = BIO_new(BIO_f_base64())) == NULL) {
- log_message(LOG_ERR, "Could not allocate base64 bio: %s", client);
- goto out;
- }
- BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
- getbio = BIO_push(b64, getbio);
- } else if (strncmp(reqbuf, "POST ", 5) != 0) {
- log_message(LOG_INFO, "Invalid request -- bad HTTP verb: %s", client);
- goto out;
- }
-
- /* Read and skip past the headers. */
- for (;;) {
- len = BIO_gets(cbio, inbuf, sizeof(inbuf));
- if (len <= 0)
- goto out;
- if ((inbuf[0] == '\r') || (inbuf[0] == '\n'))
- break;
- }
-
-# ifdef OCSP_DAEMON
- /* Clear alarm before we close the client socket */
- alarm(0);
- timeout = 0;
-# endif
-
- /* Try to read OCSP request */
- if (getbio != NULL) {
- req = d2i_OCSP_REQUEST_bio(getbio, NULL);
- BIO_free_all(getbio);
- } else {
- req = d2i_OCSP_REQUEST_bio(cbio, NULL);
- }
-
- if (req == NULL)
- log_message(LOG_ERR, "Error parsing OCSP request");
-
- *preq = req;
-
-out:
-# ifdef OCSP_DAEMON
- if (timeout > 0)
- alarm(0);
- acfd = (int)INVALID_SOCKET;
-# endif
- return 1;
+ return 0;
#endif
}
-static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp)
+static int send_ocsp_response(BIO *cbio, const OCSP_RESPONSE *resp)
{
- char http_resp[] =
- "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n"
- "Content-Length: %d\r\n\r\n";
- if (cbio == NULL)
- return 0;
- BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL));
- i2d_OCSP_RESPONSE_bio(cbio, resp);
- (void)BIO_flush(cbio);
- return 1;
+#ifndef OPENSSL_NO_SOCK
+ return http_server_send_asn1_resp(cbio, "application/ocsp-response",
+ ASN1_ITEM_rptr(OCSP_RESPONSE),
+ (const ASN1_VALUE *)resp);
+#else
+ BIO_printf(bio_err,
+ "Error sending OCSP response - sockets not supported\n");
+ return 0;
+#endif
}
#ifndef OPENSSL_NO_SOCK
diff --git a/crypto/bio/bio_lib.c b/crypto/bio/bio_lib.c
index c625833cb0..1579f7c366 100644
--- a/crypto/bio/bio_lib.c
+++ b/crypto/bio/bio_lib.c
@@ -788,7 +788,9 @@ void bio_cleanup(void)
/* Internal variant of the below BIO_wait() not calling BIOerr() */
static int bio_wait(BIO *bio, time_t max_time, unsigned int milliseconds)
{
+#ifndef OPENSSL_NO_SOCK
int fd;
+#endif
if (max_time == 0)
return 1;
diff --git a/crypto/cmp/cmp_http.c b/crypto/cmp/cmp_http.c
index 4c9f542b49..3804f2498f 100644
--- a/crypto/cmp/cmp_http.c
+++ b/crypto/cmp/cmp_http.c
@@ -58,8 +58,8 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
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),
- headers, content_type_pkix,
- (ASN1_VALUE *)req, ASN1_ITEM_rptr(OSSL_CMP_MSG),
+ 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));
diff --git a/crypto/cmp/cmp_server.c b/crypto/cmp/cmp_server.c
index 4da9a4436f..8bd3b56a26 100644
--- a/crypto/cmp/cmp_server.c
+++ b/crypto/cmp/cmp_server.c
@@ -489,9 +489,9 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
tid);
OPENSSL_free(tid);
}
- /* start of a new transaction, set transactionID and senderNonce */
- if (!OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID)
- || !ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce))
+ /* start of a new transaction, reset transactionID and senderNonce */
+ if (!OSSL_CMP_CTX_set1_transactionID(ctx, NULL)
+ || !OSSL_CMP_CTX_set1_senderNonce(ctx, NULL))
goto err;
break;
default:
@@ -594,7 +594,9 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
case OSSL_CMP_PKIBODY_GENP:
case OSSL_CMP_PKIBODY_ERROR:
/* TODO possibly support further terminating response message types */
- (void)OSSL_CMP_CTX_set1_transactionID(ctx, NULL); /* ignore any error */
+ /* prepare for next transaction, ignoring any errors here: */
+ (void)OSSL_CMP_CTX_set1_transactionID(ctx, NULL);
+ (void)OSSL_CMP_CTX_set1_senderNonce(ctx, NULL);
default: /* not closing transaction in other cases */
break;
diff --git a/crypto/http/http_client.c b/crypto/http/http_client.c
index 98be2c4947..64f877abed 100644
--- a/crypto/http/http_client.c
+++ b/crypto/http/http_client.c
@@ -222,7 +222,7 @@ static int OSSL_HTTP_REQ_CTX_content(OSSL_HTTP_REQ_CTX *rctx,
&& BIO_write(rctx->mem, req, req_len) == (int)req_len;
}
-BIO *HTTP_asn1_item2bio(const ASN1_ITEM *it, ASN1_VALUE *val)
+BIO *HTTP_asn1_item2bio(const ASN1_ITEM *it, const ASN1_VALUE *val)
{
BIO *res;
@@ -1069,7 +1069,7 @@ ASN1_VALUE *OSSL_HTTP_post_asn1(const char *server, const char *port,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type,
- ASN1_VALUE *req, const ASN1_ITEM *req_it,
+ 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)
diff --git a/crypto/http/http_local.h b/crypto/http/http_local.h
index 64b475b818..729d24e47f 100644
--- a/crypto/http/http_local.h
+++ b/crypto/http/http_local.h
@@ -27,7 +27,7 @@ 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
-BIO *HTTP_asn1_item2bio(const ASN1_ITEM *it, ASN1_VALUE *val);
+BIO *HTTP_asn1_item2bio(const ASN1_ITEM *it, const 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,
const char *path,
diff --git a/doc/man3/OSSL_HTTP_transfer.pod b/doc/man3/OSSL_HTTP_transfer.pod
index 632f48dbe8..e0adb2a1d1 100644
--- a/doc/man3/OSSL_HTTP_transfer.pod
+++ b/doc/man3/OSSL_HTTP_transfer.pod
@@ -38,7 +38,7 @@ OSSL_HTTP_parse_url
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type,
- ASN1_VALUE *req, const ASN1_ITEM *req_it,
+ 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);
diff --git a/include/openssl/http.h b/include/openssl/http.h
index 4dff008801..45c8f11d7b 100644
--- a/include/openssl/http.h
+++ b/include/openssl/http.h
@@ -56,7 +56,7 @@ ASN1_VALUE *OSSL_HTTP_post_asn1(const char *server, const char *port,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
const STACK_OF(CONF_VALUE) *headers,
const char *content_type,
- ASN1_VALUE *req, const ASN1_ITEM *req_it,
+ 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);
More information about the openssl-commits
mailing list