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 */
