Commit e99307b011 for openssl.org

commit e99307b011fb5313b6edd58e8715b8196553b040
Author: Bob Beck <beck@openssl.org>
Date:   Wed Jun 17 20:41:58 2026 -0600

    Replace strlen-then-snprintf preconditions with snprintf-return

    This restructureis the apps/lib/apps.c file-rotation helpers
    to use snprintf for truncation detection, since they now can.

    This also collapses the per-snprintf VMS ifdef into one
    SUFFIX_SEP macro because the ifdef-per-call shape was making my eyes
    bleed from all the copypasta'ed snprintf lines with only one character
    changed in the format string.

    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    MergeDate: Wed Aug 26 16:20:32 2026
    (Merged from https://github.com/openssl/openssl/pull/31640)

diff --git a/apps/lib/apps.c b/apps/lib/apps.c
index 14b6d6d814..86c69cb337 100644
--- a/apps/lib/apps.c
+++ b/apps/lib/apps.c
@@ -1738,6 +1738,16 @@ err:
     return ret;
 }

+/*
+ * Character that separates a filename from its suffix in the file-rotation
+ * helpers below.  On VMS, '.' is structural so we use '-' instead.
+ */
+#ifndef OPENSSL_SYS_VMS
+#define SUFFIX_SEP '.'
+#else
+#define SUFFIX_SEP '-'
+#endif
+
 int save_serial(const char *serialfile, const char *suffix,
     const BIGNUM *serial, ASN1_INTEGER **retai)
 {
@@ -1747,23 +1757,14 @@ int save_serial(const char *serialfile, const char *suffix,
     ASN1_INTEGER *ai = NULL;

     if (suffix == NULL) {
-        if (OPENSSL_strlcpy(buf[0], serialfile, BSIZE) >= BSIZE) {
-            BIO_puts(bio_err, "File name too long\n");
-            goto err;
-        }
+        if (OPENSSL_strlcpy(buf[0], serialfile, BSIZE) >= BSIZE)
+            goto too_long;
     } else {
-        int n = snprintf(buf[0], sizeof(buf[0]),
-#ifndef OPENSSL_SYS_VMS
-            "%s.%s",
-#else
-            "%s-%s",
-#endif
-            serialfile, suffix);
+        int n = snprintf(buf[0], sizeof(buf[0]), "%s%c%s",
+            serialfile, SUFFIX_SEP, suffix);

-        if (n < 0 || (size_t)n >= sizeof(buf[0])) {
-            BIO_puts(bio_err, "File name too long\n");
-            goto err;
-        }
+        if (n < 0 || (size_t)n >= sizeof(buf[0]))
+            goto too_long;
     }
     out = BIO_new_file(buf[0], "w");
     if (out == NULL) {
@@ -1781,6 +1782,9 @@ int save_serial(const char *serialfile, const char *suffix,
         *retai = ai;
         ai = NULL;
     }
+    goto err;
+too_long:
+    BIO_puts(bio_err, "File name too long\n");
 err:
     if (!ret)
         ERR_print_errors(bio_err);
@@ -1793,23 +1797,16 @@ int rotate_serial(const char *serialfile, const char *new_suffix,
     const char *old_suffix)
 {
     char buf[2][BSIZE];
-    size_t i, j;
-
-    i = strlen(serialfile) + strlen(old_suffix);
-    j = strlen(serialfile) + strlen(new_suffix);
-    if (i > j)
-        j = i;
-    if (j + 1 >= BSIZE) {
-        BIO_puts(bio_err, "File name too long\n");
-        goto err;
-    }
-#ifndef OPENSSL_SYS_VMS
-    snprintf(buf[0], sizeof(buf[0]), "%s.%s", serialfile, new_suffix);
-    snprintf(buf[1], sizeof(buf[1]), "%s.%s", serialfile, old_suffix);
-#else
-    snprintf(buf[0], sizeof(buf[0]), "%s-%s", serialfile, new_suffix);
-    snprintf(buf[1], sizeof(buf[1]), "%s-%s", serialfile, old_suffix);
-#endif
+    int n;
+
+    n = snprintf(buf[0], sizeof(buf[0]), "%s%c%s",
+        serialfile, SUFFIX_SEP, new_suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[0]))
+        goto too_long;
+    n = snprintf(buf[1], sizeof(buf[1]), "%s%c%s",
+        serialfile, SUFFIX_SEP, old_suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[1]))
+        goto too_long;
     if (rename(serialfile, buf[1]) < 0 && errno != ENOENT
 #ifdef ENOTDIR
         && errno != ENOTDIR
@@ -1828,6 +1825,8 @@ int rotate_serial(const char *serialfile, const char *new_suffix,
         goto err;
     }
     return 1;
+too_long:
+    BIO_puts(bio_err, "File name too long\n");
 err:
     ERR_print_errors(bio_err);
     return 0;
@@ -1892,11 +1891,7 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr)
     if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL)
         goto err;

-#ifndef OPENSSL_SYS_VMS
-    snprintf(buf, sizeof(buf), "%s.attr", dbfile);
-#else
-    snprintf(buf, sizeof(buf), "%s-attr", dbfile);
-#endif
+    snprintf(buf, sizeof(buf), "%s%cattr", dbfile, SUFFIX_SEP);
     dbattr_conf = app_load_config_quiet(buf);

     retdb = app_malloc(sizeof(*retdb), "new DB");
@@ -1968,22 +1963,20 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db)
 {
     char buf[3][BSIZE];
     BIO *out;
-    int j;
-
-    j = (int)(strlen(dbfile) + strlen(suffix));
-    if (j + 6 >= BSIZE) {
-        BIO_puts(bio_err, "File name too long\n");
-        goto err;
-    }
-#ifndef OPENSSL_SYS_VMS
-    snprintf(buf[2], sizeof(buf[2]), "%s.attr", dbfile);
-    snprintf(buf[1], sizeof(buf[1]), "%s.attr.%s", dbfile, suffix);
-    snprintf(buf[0], sizeof(buf[0]), "%s.%s", dbfile, suffix);
-#else
-    snprintf(buf[2], sizeof(buf[2]), "%s-attr", dbfile);
-    snprintf(buf[1], sizeof(buf[1]), "%s-attr-%s", dbfile, suffix);
-    snprintf(buf[0], sizeof(buf[0]), "%s-%s", dbfile, suffix);
-#endif
+    int j, n;
+
+    n = snprintf(buf[2], sizeof(buf[2]), "%s%cattr",
+        dbfile, SUFFIX_SEP);
+    if (n < 0 || (size_t)n >= sizeof(buf[2]))
+        goto too_long;
+    n = snprintf(buf[1], sizeof(buf[1]), "%s%cattr%c%s",
+        dbfile, SUFFIX_SEP, SUFFIX_SEP, suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[1]))
+        goto too_long;
+    n = snprintf(buf[0], sizeof(buf[0]), "%s%c%s",
+        dbfile, SUFFIX_SEP, suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[0]))
+        goto too_long;
     out = BIO_new_file(buf[0], "w");
     if (out == NULL) {
         perror(dbfile);
@@ -2006,6 +1999,8 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db)
     BIO_free(out);

     return 1;
+too_long:
+    BIO_puts(bio_err, "File name too long\n");
 err:
     ERR_print_errors(bio_err);
     return 0;
@@ -2015,29 +2010,28 @@ int rotate_index(const char *dbfile, const char *new_suffix,
     const char *old_suffix)
 {
     char buf[5][BSIZE];
-    size_t i, j;
-
-    i = strlen(dbfile) + strlen(old_suffix);
-    j = strlen(dbfile) + strlen(new_suffix);
-    if (i > j)
-        j = i;
-    if (j + 6 >= BSIZE) {
-        BIO_puts(bio_err, "File name too long\n");
-        goto err;
-    }
-#ifndef OPENSSL_SYS_VMS
-    snprintf(buf[4], sizeof(buf[4]), "%s.attr", dbfile);
-    snprintf(buf[3], sizeof(buf[3]), "%s.attr.%s", dbfile, old_suffix);
-    snprintf(buf[2], sizeof(buf[2]), "%s.attr.%s", dbfile, new_suffix);
-    snprintf(buf[1], sizeof(buf[1]), "%s.%s", dbfile, old_suffix);
-    snprintf(buf[0], sizeof(buf[0]), "%s.%s", dbfile, new_suffix);
-#else
-    snprintf(buf[4], sizeof(buf[4]), "%s-attr", dbfile);
-    snprintf(buf[3], sizeof(buf[3]), "%s-attr-%s", dbfile, old_suffix);
-    snprintf(buf[2], sizeof(buf[2]), "%s-attr-%s", dbfile, new_suffix);
-    snprintf(buf[1], sizeof(buf[1]), "%s-%s", dbfile, old_suffix);
-    snprintf(buf[0], sizeof(buf[0]), "%s-%s", dbfile, new_suffix);
-#endif
+    int n;
+
+    n = snprintf(buf[4], sizeof(buf[4]), "%s%cattr",
+        dbfile, SUFFIX_SEP);
+    if (n < 0 || (size_t)n >= sizeof(buf[4]))
+        goto too_long;
+    n = snprintf(buf[3], sizeof(buf[3]), "%s%cattr%c%s",
+        dbfile, SUFFIX_SEP, SUFFIX_SEP, old_suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[3]))
+        goto too_long;
+    n = snprintf(buf[2], sizeof(buf[2]), "%s%cattr%c%s",
+        dbfile, SUFFIX_SEP, SUFFIX_SEP, new_suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[2]))
+        goto too_long;
+    n = snprintf(buf[1], sizeof(buf[1]), "%s%c%s",
+        dbfile, SUFFIX_SEP, old_suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[1]))
+        goto too_long;
+    n = snprintf(buf[0], sizeof(buf[0]), "%s%c%s",
+        dbfile, SUFFIX_SEP, new_suffix);
+    if (n < 0 || (size_t)n >= sizeof(buf[0]))
+        goto too_long;
     if (rename(dbfile, buf[1]) < 0 && errno != ENOENT
 #ifdef ENOTDIR
         && errno != ENOTDIR
@@ -2073,6 +2067,8 @@ int rotate_index(const char *dbfile, const char *new_suffix,
         goto err;
     }
     return 1;
+too_long:
+    BIO_puts(bio_err, "File name too long\n");
 err:
     ERR_print_errors(bio_err);
     return 0;
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index e05c5832e3..49831e812a 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -981,22 +981,20 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack,
         if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
             continue;
 #endif
-        if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) {
-            ERR_raise(ERR_LIB_SSL, SSL_R_PATH_TOO_LONG);
-            goto err;
-        }
 #ifdef OPENSSL_SYS_VMS
         r = snprintf(buf, sizeof(buf), "%s%s", dir, filename);
 #else
         r = snprintf(buf, sizeof(buf), "%s/%s", dir, filename);
 #endif
+        if (r < 0 || (size_t)r >= sizeof(buf)) {
+            ERR_raise(ERR_LIB_SSL, SSL_R_PATH_TOO_LONG);
+            goto err;
+        }
 #ifndef OPENSSL_NO_POSIX_IO
         /* Skip subdirectories */
         if (!stat(buf, &st) && S_ISDIR(st.st_mode))
             continue;
 #endif
-        if (r <= 0 || r >= (int)sizeof(buf))
-            goto err;
         if (!add_file_cert_subjects_to_stack(stack, buf, name_hash))
             goto err;
     }