git: 824098cc2559 - main - security/libressl-devel: Security fix for OCSP
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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 */