Commit 465fd32d33 for openssl.org

commit 465fd32d3374a7197107ebd9ad09f8844a7d496d
Author: Tom Gautot <tgautot.off@gmail.com>
Date:   Tue Jan 27 23:01:37 2026 +0100

    OSSL_HTTP_REQ_CTX_nbio(): check for clear Content-Type mismatch

    Fixes #29748

    Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    Reviewed-by: Tomas Mraz <tomas@openssl.org>
    MergeDate: Thu Mar  5 18:04:24 2026
    (Merged from https://github.com/openssl/openssl/pull/29829)

diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 43ddba739d..902f432299 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -820,6 +820,7 @@ EVP_R_XTS_DATA_UNIT_IS_TOO_LARGE:191:xts data unit is too large
 EVP_R_XTS_DUPLICATED_KEYS:192:xts duplicated keys
 HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN:108:asn1 len exceeds max resp len
 HTTP_R_CONNECT_FAILURE:100:connect failure
+HTTP_R_CONTENT_TYPE_MISMATCH:131:content type mismatch
 HTTP_R_ERROR_PARSING_ASN1_LENGTH:109:error parsing asn1 length
 HTTP_R_ERROR_PARSING_CONTENT_LENGTH:119:error parsing content length
 HTTP_R_ERROR_PARSING_URL:101:error parsing url
diff --git a/crypto/http/http_client.c b/crypto/http/http_client.c
index 181b50e688..00e5bf77d7 100644
--- a/crypto/http/http_client.c
+++ b/crypto/http/http_client.c
@@ -551,6 +551,7 @@ static int may_still_retry(time_t max_time, int *ptimeout)
 int OSSL_HTTP_REQ_CTX_nbio(OSSL_HTTP_REQ_CTX *rctx)
 {
     int i, found_expected_ct = 0, found_keep_alive = 0;
+    int status_code = 0;
     int got_text = 1;
     long n;
     size_t resp_len = 0;
@@ -751,8 +752,8 @@ next_io:

         /* First line in response header */
         if (rctx->state == OHS_FIRSTLINE) {
-            i = parse_http_line1(buf, &found_keep_alive);
-            switch (i) {
+            status_code = parse_http_line1(buf, &found_keep_alive);
+            switch (status_code) {
             case HTTP_STATUS_CODE_OK:
                 rctx->state = OHS_HEADERS;
                 goto next_line;
@@ -767,7 +768,7 @@ next_io:
                 /* fall through */
             default:
                 /* must return content if status >= 400 */
-                rctx->state = i < HTTP_STATUS_CODES_NONFATAL_ERROR
+                rctx->state = status_code < HTTP_STATUS_CODES_NONFATAL_ERROR
                     ? OHS_HEADERS_ERROR
                     : OHS_HEADERS;
                 goto next_line; /* continue parsing, also on HTTP error */
@@ -797,6 +798,17 @@ next_io:
             }
             if (OPENSSL_strcasecmp(key, "Content-Type") == 0) {
                 got_text = HAS_CASE_PREFIX(value, "text/");
+                if (got_text
+                    && rctx->state == OHS_HEADERS
+                    && rctx->expect_asn1
+                    && (status_code >= HTTP_STATUS_CODES_NONFATAL_ERROR
+                        || status_code == HTTP_STATUS_CODE_OK)) {
+                    ERR_raise_data(ERR_LIB_HTTP, HTTP_R_CONTENT_TYPE_MISMATCH,
+                        "expected ASN.1 content but got http code %d with Content-Type: %s",
+                        status_code, value);
+                    rctx->state = OHS_HEADERS_ERROR;
+                    goto next_line;
+                }
                 if (rctx->state == OHS_HEADERS
                     && rctx->expected_ct != NULL) {
                     const char *semicolon;
diff --git a/crypto/http/http_err.c b/crypto/http/http_err.c
index 947a403d60..8598dd1ff4 100644
--- a/crypto/http/http_err.c
+++ b/crypto/http/http_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2026 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
@@ -20,6 +20,8 @@ static const ERR_STRING_DATA HTTP_str_reasons[] = {
     { ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN),
         "asn1 len exceeds max resp len" },
     { ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_CONNECT_FAILURE), "connect failure" },
+    { ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_CONTENT_TYPE_MISMATCH),
+        "content type mismatch" },
     { ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_ERROR_PARSING_ASN1_LENGTH),
         "error parsing asn1 length" },
     { ERR_PACK(ERR_LIB_HTTP, 0, HTTP_R_ERROR_PARSING_CONTENT_LENGTH),
diff --git a/include/crypto/httperr.h b/include/crypto/httperr.h
index f5550aa167..94d812295c 100644
--- a/include/crypto/httperr.h
+++ b/include/crypto/httperr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2026 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
diff --git a/include/openssl/httperr.h b/include/openssl/httperr.h
index adac950186..4c1cc6ad6b 100644
--- a/include/openssl/httperr.h
+++ b/include/openssl/httperr.h
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2026 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
@@ -21,6 +21,7 @@
  */
 #define HTTP_R_ASN1_LEN_EXCEEDS_MAX_RESP_LEN 108
 #define HTTP_R_CONNECT_FAILURE 100
+#define HTTP_R_CONTENT_TYPE_MISMATCH 131
 #define HTTP_R_ERROR_PARSING_ASN1_LENGTH 109
 #define HTTP_R_ERROR_PARSING_CONTENT_LENGTH 119
 #define HTTP_R_ERROR_PARSING_URL 101