git: 824098cc2559 - main - security/libressl-devel: Security fix for OCSP

From: Bernard Spil <brnrd_at_FreeBSD.org>
Date: Sat, 31 Oct 2026 17:38:16 UTC
The branch main has been updated by brnrd:

URL: https://cgit.FreeBSD.org/ports/commit/?id=824098cc2559165850e6baab54bf6b87f02ba37d

commit 824098cc2559165850e6baab54bf6b87f02ba37d
Author:     Bernard Spil <brnrd@FreeBSD.org>
AuthorDate: 2026-10-31 17:36:47 +0000
Commit:     Bernard Spil <brnrd@FreeBSD.org>
CommitDate: 2026-10-31 17:36:47 +0000

    security/libressl-devel: Security fix for OCSP
    
    Security:       aafad06c-d519-11f1-8135-8447094a420f
    MFH:            2026Q4
---
 security/libressl-devel/Makefile                   |   1 +
 security/libressl-devel/files/patch-apps_ocspcheck | 300 +++++++++++++++++++++
 security/libressl-devel/files/patch-crypto_ocsp    | 134 +++++++++
 3 files changed, 435 insertions(+)

diff --git a/security/libressl-devel/Makefile b/security/libressl-devel/Makefile
index c37537fa598e..809e725c8c19 100644
--- a/security/libressl-devel/Makefile
+++ b/security/libressl-devel/Makefile
@@ -1,5 +1,6 @@
 PORTNAME=	libressl
 DISTVERSION=	4.4.0
+PORTREVISION=	1
 CATEGORIES=	security devel
 MASTER_SITES=	OPENBSD/LibreSSL
 PKGNAMESUFFIX=	-devel
diff --git a/security/libressl-devel/files/patch-apps_ocspcheck b/security/libressl-devel/files/patch-apps_ocspcheck
new file mode 100644
index 000000000000..6bf5b7891a26
--- /dev/null
+++ b/security/libressl-devel/files/patch-apps_ocspcheck
@@ -0,0 +1,300 @@
+diff --git a/src/usr.sbin/ocspcheck/http.c b/src/usr.sbin/ocspcheck/http.c
+index 46b01f1ec..1a8158f74 100644
+--- apps/ocspcheck/http.c.orig
++++ apps/ocspcheck/http.c
+@@ -1,4 +1,4 @@
+-/*	$Id: http.c,v 1.17 2023/04/19 12:58:16 jsg Exp $ */
++/*	$Id: http.c,v 1.21 2026/10/16 06:42:46 kenjiro Exp $ */
+ /*
+  * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
+  *
+@@ -34,6 +34,10 @@
+ 
+ #include "http.h"
+ 
++#define HTTP_MAXHEADERLENGTH	(64 * 1024)
++
++#define HTTP_MAX_BODY_SIZE	(20 * 1024)
++
+ /*
+  * A buffer for transferring HTTP/S data.
+  */
+@@ -218,7 +222,7 @@ http_free(struct http *http)
+ 
+ struct http *
+ http_alloc(const struct source *addrs, size_t addrsz,
+-    const char *host, short port, const char *path)
++    const char *host, short port, int use_tls, const char *path)
+ {
+ 	struct sockaddr_storage ss;
+ 	int		 family, fd, c;
+@@ -296,7 +300,7 @@ again:
+ 
+ 	/* If necessary, do our TLS setup. */
+ 
+-	if (port != 443) {
++	if (!use_tls) {
+ 		http->writer = dosyswrite;
+ 		http->reader = dosysread;
+ 		return http;
+@@ -416,6 +420,11 @@ http_body_read(const struct http *http, struct httpxfer *trans, size_t *sz)
+ 		else if (ssz == 0)
+ 			break;
+ 
++		if (trans->bbufsz > HTTP_MAX_BODY_SIZE ||
++		    (size_t)ssz > HTTP_MAX_BODY_SIZE - trans->bbufsz) {
++			warnx("%s: body too large", http->src.ip);
++			return NULL;
++		}
+ 		pp = recallocarray(trans->bbuf,
+ 		    trans->bbufsz, trans->bbufsz + ssz, 1);
+ 		if (pp == NULL) {
+@@ -611,6 +620,10 @@ http_head_read(const struct http *http, struct httpxfer *trans, size_t *sz)
+ 			return NULL;
+ 		else if (ssz == 0)
+ 			break;
++		if ((size_t)ssz > HTTP_MAXHEADERLENGTH - trans->hbufsz) {
++			warnx("%s: header too large", http->src.ip);
++			return NULL;
++		}
+ 		pp = realloc(trans->hbuf, trans->hbufsz + ssz);
+ 		if (pp == NULL) {
+ 			warn("realloc");
+@@ -672,7 +685,7 @@ http_get_free(struct httpget *g)
+ 
+ struct httpget *
+ http_get(const struct source *addrs, size_t addrsz, const char *domain,
+-    short port, const char *path, const void *post, size_t postsz)
++    short port, int use_tls, const char *path, const void *post, size_t postsz)
+ {
+ 	struct http	*h;
+ 	struct httpxfer	*x;
+@@ -682,7 +695,7 @@ http_get(const struct source *addrs, size_t addrsz, const char *domain,
+ 	int		 code;
+ 	char		*bod, *headr;
+ 
+-	h = http_alloc(addrs, addrsz, domain, port, path);
++	h = http_alloc(addrs, addrsz, domain, port, use_tls, path);
+ 	if (h == NULL)
+ 		return NULL;
+ 
+@@ -729,49 +742,3 @@ http_get(const struct source *addrs, size_t addrsz, const char *domain,
+ 	g->http = h;
+ 	return g;
+ }
+-
+-#if 0
+-int
+-main(void)
+-{
+-	struct httpget	*g;
+-	struct httphead	*httph;
+-	size_t		 i, httphsz;
+-	struct source	 addrs[2];
+-	size_t		 addrsz;
+-
+-#if 0
+-	addrs[0].ip = "127.0.0.1";
+-	addrs[0].family = 4;
+-	addrsz = 1;
+-#else
+-	addrs[0].ip = "2a00:1450:400a:806::2004";
+-	addrs[0].family = 6;
+-	addrs[1].ip = "193.135.3.123";
+-	addrs[1].family = 4;
+-	addrsz = 2;
+-#endif
+-
+-	if (http_init() == -1)
+-		errx(EXIT_FAILURE, "http_init");
+-
+-#if 0
+-	g = http_get(addrs, addrsz, "localhost", 80, "/index.html");
+-#else
+-	g = http_get(addrs, addrsz, "www.google.ch", 80, "/index.html",
+-	    NULL, 0);
+-#endif
+-
+-	if (g == NULL)
+-		errx(EXIT_FAILURE, "http_get");
+-
+-	httph = http_head_parse(g->http, g->xfer, &httphsz);
+-	warnx("code: %d", g->code);
+-
+-	for (i = 0; i < httphsz; i++)
+-		warnx("head: [%s]=[%s]", httph[i].key, httph[i].val);
+-
+-	http_get_free(g);
+-	return (EXIT_SUCCESS);
+-}
+-#endif
+diff --git a/src/usr.sbin/ocspcheck/http.h b/src/usr.sbin/ocspcheck/http.h
+index 17541b436..a0392b8bb 100644
+--- apps/ocspcheck/http.h.orig
++++ apps/ocspcheck/http.h
+@@ -1,4 +1,4 @@
+-/*	$Id: http.h,v 1.3 2017/01/25 13:52:53 inoguchi Exp $ */
++/*	$Id: http.h,v 1.4 2026/10/16 06:18:23 kenjiro Exp $ */
+ /*
+  * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
+  *
+@@ -65,13 +65,13 @@ int		 http_init(void);
+ 
+ /* Convenience functions. */
+ struct httpget	*http_get(const struct source *, size_t,
+-			const char *, short, const char *,
++			const char *, short, int, const char *,
+ 			const void *, size_t);
+ void		 http_get_free(struct httpget *);
+ 
+ /* Allocation and release. */
+ struct http	*http_alloc(const struct source *, size_t,
+-			const char *, short, const char *);
++			const char *, short, int, const char *);
+ void		 http_free(struct http *);
+ struct httpxfer	*http_open(const struct http *, const void *, size_t);
+ void		 http_close(struct httpxfer *);
+diff --git a/src/usr.sbin/ocspcheck/ocspcheck.c b/src/usr.sbin/ocspcheck/ocspcheck.c
+index 7de764f6b..5d82ca88f 100644
+--- apps/ocspcheck/ocspcheck.c.orig
++++ apps/ocspcheck/ocspcheck.c
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: ocspcheck.c,v 1.37 2026/09/19 01:18:07 tb Exp $ */
++/* $OpenBSD: ocspcheck.c,v 1.41 2026/10/19 23:18:26 kenjiro Exp $ */
+ 
+ /*
+  * Copyright (c) 2017,2020 Bob Beck <beck@openbsd.org>
+@@ -21,6 +21,7 @@
+ #include <sys/socket.h>
+ #include <sys/stat.h>
+ 
++#include <ctype.h>
+ #include <err.h>
+ #include <fcntl.h>
+ #include <limits.h>
+@@ -120,25 +121,45 @@ host_dns(const char *s, struct addr vec[MAX_SERVERS_DNS])
+ 	return vecsz;
+ }
+ 
++static int
++ocsp_url_chars_only(const char *url)
++{
++	size_t	i, len;
++
++	/* Reject control characters before using the URL in an HTTP request. */
++	len = strlen(url);
++	for (i = 0; i < len; i++) {
++		if (!isascii((unsigned char)url[i]))
++			return 0;
++		if (!isalnum((unsigned char)url[i]) &&
++		    !ispunct((unsigned char)url[i]))
++			return 0;
++	}
++
++	return 1;
++}
++
+ /*
+  * Extract the domain and port from a URL.
+  * The url must be formatted as schema://address[/stuff].
+  * This returns NULL on failure.
+  */
+ static char *
+-url2host(const char *host, short *port, char **path)
++url2host(const char *host, short *port, char **path, int *use_tls)
+ {
+ 	char	*url, *ep;
+ 
+ 	/* We only understand HTTP and HTTPS. */
+ 
+ 	if (strncmp(host, "https://", 8) == 0) {
++		*use_tls = 1;
+ 		*port = 443;
+ 		if ((url = strdup(host + 8)) == NULL) {
+ 			warn("strdup");
+ 			return (NULL);
+ 		}
+ 	} else if (strncmp(host, "http://", 7) == 0) {
++		*use_tls = 0;
+ 		*port = 80;
+ 		if ((url = strdup(host + 7)) == NULL) {
+ 			warn("strdup");
+@@ -312,11 +333,12 @@ static ocsp_request *
+ ocsp_request_new_from_cert(const char *cadir, char *file, int nonce)
+ {
+ 	X509 *cert;
+-	int count = 0;
++	int count = 0, i;
+ 	OCSP_CERTID *id = NULL;
+ 	ocsp_request *request = NULL;
+ 	const EVP_MD *cert_id_md = NULL;
+ 	const X509 *issuer;
++	const char *url;
+ 	STACK_OF(OPENSSL_STRING) *urls = NULL;
+ 
+ 	if ((request = calloc(1, sizeof(ocsp_request))) == NULL) {
+@@ -355,7 +377,15 @@ ocsp_request_new_from_cert(const char *cadir, char *file, int nonce)
+ 		warnx("Certificate in %s contains no OCSP url", file);
+ 		goto err;
+ 	}
+-	if ((request->url = strdup(sk_OPENSSL_STRING_value(urls, 0))) == NULL)
++	for (i = 0; i < sk_OPENSSL_STRING_num(urls); i++) {
++		url = sk_OPENSSL_STRING_value(urls, i);
++		if (!ocsp_url_chars_only(url)) {
++			warnx("Invalid OCSP url from %s", file);
++			goto err;
++		}
++	}
++	url = sk_OPENSSL_STRING_value(urls, 0);
++	if ((request->url = strdup(url)) == NULL)
+ 		goto err;
+ 	X509_email_free(urls);
+ 	urls = NULL;
+@@ -479,6 +509,10 @@ validate_response(char *buf, size_t size, ocsp_request *request,
+ 			warnx("Certificate revoked at: %s", ctime(&rev_t));
+ 		goto err;
+ 	}
++	if (cert_status != V_OCSP_CERTSTATUS_GOOD) {
++		warnx("Invalid OCSP reply: certificate status is not good");
++		goto err;
++	}
+ 	if ((this_t = parse_ocsp_time(thisupd)) == -1) {
+ 		warnx("unable to parse this update time in OCSP reply");
+ 		goto err;
+@@ -552,7 +586,8 @@ main(int argc, char **argv)
+ 	    *instaple = NULL, *infile = NULL;
+ 	struct addr addrs[MAX_SERVERS_DNS] = {{0}};
+ 	struct source sources[MAX_SERVERS_DNS];
+-	int i, ch, staplefd = -1, infd = -1, nonce = 1;
++	int i, ch, use_tls;
++	int staplefd = -1, infd = -1, nonce = 1;
+ 	ocsp_request *request = NULL;
+ 	size_t rescount, instaplesz = 0;
+ 	struct httpget *hget;
+@@ -641,7 +676,7 @@ main(int argc, char **argv)
+ 
+ 	dspew("Built an %zu byte ocsp request\n", request->size);
+ 
+-	if ((host = url2host(request->url, &port, &path)) == NULL)
++	if ((host = url2host(request->url, &port, &path, &use_tls)) == NULL)
+ 		errx(1, "Invalid OCSP url %s from %s", request->url,
+ 		    certfile);
+ 
+@@ -649,7 +684,7 @@ main(int argc, char **argv)
+ 		/* Get a new OCSP response from the indicated server */
+ 
+ 		vspew("Using %s to host %s, port %d, path %s\n",
+-		    port == 443 ? "https" : "http", host, port, path);
++		    use_tls ? "https" : "http", host, port, path);
+ 
+ 		rescount = host_dns(host, addrs);
+ 		for (i = 0; i < rescount; i++) {
+@@ -661,7 +696,7 @@ main(int argc, char **argv)
+ 		 * Do an HTTP post to send our request to the OCSP
+ 		 * server, and hopefully get an answer back
+ 		 */
+-		hget = http_get(sources, rescount, host, port, path,
++		hget = http_get(sources, rescount, host, port, use_tls, path,
+ 		    request->data, request->size);
+ 		if (hget == NULL)
+ 			errx(1, "http_get");
diff --git a/security/libressl-devel/files/patch-crypto_ocsp b/security/libressl-devel/files/patch-crypto_ocsp
new file mode 100644
index 000000000000..15f9479b50d3
--- /dev/null
+++ b/security/libressl-devel/files/patch-crypto_ocsp
@@ -0,0 +1,134 @@
+From 95ff90f528a595dbc44aba777ccd1cd6ec4c6472 Mon Sep 17 00:00:00 2001
+From: tb <>
+Date: Tue, 20 Oct 2026 04:39:15 +0000
+Subject: [PATCH] ocsp: validate URI characters in OCSP
+
+In OCSP_sendreq_new() and OCSP_parse_url() reject URIs containing control
+characters. Since these APIs are typically used to create a POST request
+to an untrusted cert's Authority Information Access accessLocation URI,
+lack of sanitization meant that there is a path for header injection via
+CRLF and similar tricks.
+
+Reported by Aziz ELBELAYCHY (also for ocspcheck.c r1.40)
+
+ok beck kenjiro
+---
+ src/lib/libcrypto/ocsp/ocsp_ht.c    | 11 ++++++++---
+ src/lib/libcrypto/ocsp/ocsp_lib.c   | 26 +++++++++++++++++++++++++-
+ src/lib/libcrypto/ocsp/ocsp_local.h |  4 +++-
+ 3 files changed, 36 insertions(+), 5 deletions(-)
+
+diff --git a/src/lib/libcrypto/ocsp/ocsp_ht.c b/src/lib/libcrypto/ocsp/ocsp_ht.c
+index db83b35518ff..3b9c53d27bd3 100644
+--- crypto/ocsp/ocsp_ht.c
++++ crypto/ocsp/ocsp_ht.c
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: ocsp_ht.c,v 1.28 2025/05/10 05:54:38 tb Exp $ */
++/* $OpenBSD: ocsp_ht.c,v 1.29 2026/10/20 04:39:15 tb Exp $ */
+ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+  * project 2006.
+  */
+@@ -66,6 +66,7 @@
+ #include <openssl/buffer.h>
+ 
+ #include "err_local.h"
++#include "ocsp_local.h"
+ 
+ /* Stateful OCSP request code, supporting non-blocking I/O */
+ 
+@@ -158,6 +159,12 @@ OCSP_sendreq_new(BIO *io, const char *path, OCSP_REQUEST *req, int maxline)
+ {
+ 	OCSP_REQ_CTX *rctx;
+ 
++	if (path == NULL)
++		path = "/";
++
++	if (!ocsp_uri_chars_only(path))
++		return NULL;
++
+ 	rctx = malloc(sizeof(OCSP_REQ_CTX));
+ 	if (rctx == NULL)
+ 		return NULL;
+@@ -178,8 +185,6 @@ OCSP_sendreq_new(BIO *io, const char *path, OCSP_REQUEST *req, int maxline)
+ 		free(rctx);
+ 		return NULL;
+ 	}
+-	if (!path)
+-		path = "/";
+ 
+ 	if (BIO_printf(rctx->mem, "POST %s HTTP/1.0\r\n", path) <= 0) {
+ 		free(rctx->iobuf);
+diff --git a/src/lib/libcrypto/ocsp/ocsp_lib.c b/src/lib/libcrypto/ocsp/ocsp_lib.c
+index dfa002a5946d..3b25adc42f38 100644
+--- crypto/ocsp/ocsp_lib.c
++++ crypto/ocsp/ocsp_lib.c
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: ocsp_lib.c,v 1.29 2025/05/10 05:54:38 tb Exp $ */
++/* $OpenBSD: ocsp_lib.c,v 1.30 2026/10/20 04:39:15 tb Exp $ */
+ /* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
+  * project. */
+ 
+@@ -61,6 +61,7 @@
+  *
+  */
+ 
++#include <ctype.h>
+ #include <stdio.h>
+ #include <string.h>
+ 
+@@ -184,6 +185,24 @@ OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b)
+ }
+ LCRYPTO_ALIAS(OCSP_id_cmp);
+ 
++int
++ocsp_uri_chars_only(const char *str)
++{
++	size_t i, len;
++
++	len = strlen(str);
++
++	for (i = 0; i < len; i++) {
++		if (!isascii((unsigned char)str[i]))
++			return 0;
++		if (!isalnum((unsigned char)str[i]) &&
++		    !ispunct((unsigned char)str[i]))
++			return 0;
++	}
++
++	return 1;
++}
++
+ /* Parse a URL and split it up into host, port and path components and whether
+  * it is SSL.
+  */
+@@ -196,6 +215,11 @@ OCSP_parse_url(const char *url, char **phost, char **pport, char **ppath,
+ 	*phost = *pport = *ppath = NULL;
+ 	*pssl = 0;
+ 
++	if (!ocsp_uri_chars_only(url)) {
++		OCSPerror(OCSP_R_ERROR_PARSING_URL);
++		return 0;
++	}
++
+ 	if (strncmp(url, "https://", 8) == 0) {
+ 		*pssl = 1;
+ 		host = strdup(url + 8);
+diff --git a/src/lib/libcrypto/ocsp/ocsp_local.h b/src/lib/libcrypto/ocsp/ocsp_local.h
+index bd933b19156c..d252f33f5ea6 100644
+--- crypto/ocsp/ocsp_local.h
++++ crypto/ocsp/ocsp_local.h
+@@ -1,4 +1,4 @@
+-/* $OpenBSD: ocsp_local.h,v 1.2 2022/01/14 08:32:26 tb Exp $ */
++/* $OpenBSD: ocsp_local.h,v 1.3 2026/10/20 04:39:15 tb Exp $ */
+ /* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
+  * project. */
+ 
+@@ -286,6 +286,8 @@ struct ocsp_service_locator_st {
+     ASN1_item_verify(&OCSP_RESPDATA_it, \
+ 	(a)->signatureAlgorithm, (a)->signature, (a)->tbsResponseData, (r))
+ 
++int ocsp_uri_chars_only(const char *str);
++
+ __END_HIDDEN_DECLS
+ 
+ #endif /* !HEADER_OCSP_LOCAL_H */