Commit 833efe31fc for openssl.org
commit 833efe31fc163fb6216d6406396168cb87cea403
Author: Mounir IDRASSI <mounir.idrassi@idrix.fr>
Date: Thu Jun 25 22:09:30 2026 +0900
Remove remaining atoi()/atol() calls
Remove the remaining direct atoi()/atol() uses across apps, libcrypto,
libssl, providers, demos and tests, and route the replacements through
checked helpers instead of open-coding the conversion at each call site:
- apps use the existing opt_int()/opt_long()/opt_int_arg() parsers;
- libcrypto and provider code use the new internal ossl_strtol()/
ossl_strtoint() helpers, a checked (and, for ossl_strtoint(),
narrowing) signed counterpart to the public OPENSSL_strtoul();
- libssl, demos and tests use OPENSSL_strtoul(); the test code shares
a single test_strtoint() helper rather than repeating the bound check
and cast per file;
- unsigned values use OPENSSL_strtoul(), with call-site-specific range
checks before narrowing where the destination type requires it.
Reject conversion failures and narrow through the helpers rather than
acting on garbage, and preserve the signed RSA-PSS saltlen sentinels
while rejecting invalid numeric strings. Add regression coverage for the
invalid RSA-PSS saltlen string path.
Fixes #8216
Assisted-by: OpenCode:GLM-5.2
Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Wed Jul 29 17:02:18 2026
(Merged from https://github.com/openssl/openssl/pull/31731)
diff --git a/apps/ca.c b/apps/ca.c
index 8f98bc9a6a..c7b5a1c22d 100644
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -484,13 +484,16 @@ int ca_main(int argc, char **argv)
crl_nextupdate = opt_arg();
break;
case OPT_CRLDAYS:
- crldays = atol(opt_arg());
+ if (!opt_long(opt_arg(), &crldays))
+ goto opthelp;
break;
case OPT_CRLHOURS:
- crlhours = atol(opt_arg());
+ if (!opt_long(opt_arg(), &crlhours))
+ goto opthelp;
break;
case OPT_CRLSEC:
- crlsec = atol(opt_arg());
+ if (!opt_long(opt_arg(), &crlsec))
+ goto opthelp;
break;
case OPT_INFILES:
req = 1;
diff --git a/apps/cmp.c b/apps/cmp.c
index abe6de5cb9..e75ed35a48 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -3706,9 +3706,13 @@ static int handle_opts_upfront(int argc, char **argv)
opt_section = argv[++i];
else if (strcmp(argv[i] + 1,
cmp_options[OPT_VERBOSITY - OPT_HELP].name)
- == 0
- && !set_verbosity(atoi(argv[++i])))
- return 0;
+ == 0) {
+ int level;
+
+ ++i;
+ if (!opt_int(argv[i], &level) || !set_verbosity(level))
+ return 0;
+ }
}
}
if (opt_section[0] == '\0') /* empty string */
diff --git a/apps/lib/apps.c b/apps/lib/apps.c
index 63a8c8c00d..5d082992ec 100644
--- a/apps/lib/apps.c
+++ b/apps/lib/apps.c
@@ -252,10 +252,8 @@ static char *app_get_pass(const char *arg, int keepbio)
} else if (CHECK_AND_SKIP_PREFIX(arg, "fd:")) {
BIO *btmp;
- i = atoi(arg);
- if (i >= 0)
- pwdbio = BIO_new_fd(i, BIO_NOCLOSE);
- if ((i < 0) || pwdbio == NULL) {
+ if (!opt_int(arg, &i) || i < 0
+ || (pwdbio = BIO_new_fd(i, BIO_NOCLOSE)) == NULL) {
BIO_printf(bio_err, "Can't access file descriptor %s\n", arg);
return NULL;
}
diff --git a/apps/req.c b/apps/req.c
index 83ac38ef86..19933ea352 100644
--- a/apps/req.c
+++ b/apps/req.c
@@ -1557,10 +1557,12 @@ static EVP_PKEY_CTX *set_keygen_ctx(const char *gstr,
/* Treat the second part of gstr, if there is one */
if (gstr != NULL) {
/* If the second part starts with a digit, we assume it's a size */
- if (!expect_paramfile && gstr[0] >= '0' && gstr[0] <= '9')
- keylen = atol(gstr);
- else
+ if (!expect_paramfile && gstr[0] >= '0' && gstr[0] <= '9') {
+ if (!opt_long(gstr, &keylen))
+ return NULL;
+ } else {
paramfile = gstr;
+ }
}
if (paramfile != NULL) {
diff --git a/apps/s_client.c b/apps/s_client.c
index 65aff3eb42..80bb0f5305 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <limits.h>
#include <openssl/e_os2.h>
#include "internal/nelem.h"
#include "internal/sockets.h" /* for openssl_fdset() */
@@ -1520,7 +1521,8 @@ int s_client_main(int argc, char **argv)
break;
case OPT_MTU:
#ifndef OPENSSL_NO_DTLS
- socket_mtu = atol(opt_arg());
+ if (!opt_long(opt_arg(), &socket_mtu))
+ goto opthelp;
#endif
break;
case OPT_FALLBACKSCSV:
@@ -1625,7 +1627,20 @@ int s_client_main(int argc, char **argv)
len = (int)strlen(p);
for (start = 0, i = 0; i <= len; ++i) {
if (i == len || p[i] == ',') {
- serverinfo_types[serverinfo_count] = atoi(p + start);
+ char *end;
+ unsigned long ul;
+
+ /*
+ * Parse only the current comma-separated component.
+ * OPENSSL_strtoul() with an endptr consumes the leading
+ * digits; we require it to stop exactly at the delimiter
+ * (or NUL) and to fit in an unsigned short.
+ */
+ if (!OPENSSL_strtoul(p + start, &end, 10, &ul)
+ || end != p + i
+ || ul > USHRT_MAX)
+ goto opthelp;
+ serverinfo_types[serverinfo_count] = (unsigned short)ul;
if (++serverinfo_count == MAX_SI_TYPES)
break;
start = i + 1;
diff --git a/apps/s_server.c b/apps/s_server.c
index 4d99e5442b..2fc193980c 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -1885,7 +1885,7 @@ int s_server_main(int argc, char *argv[])
break;
#endif
case OPT_NACCEPT:
- naccept = atol(opt_arg());
+ naccept = opt_int_arg();
break;
case OPT_VERIFY:
s_server_verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
@@ -2254,7 +2254,8 @@ int s_server_main(int argc, char *argv[])
break;
case OPT_MTU:
#ifndef OPENSSL_NO_DTLS
- socket_mtu = atol(opt_arg());
+ if (!opt_long(opt_arg(), &socket_mtu))
+ goto opthelp;
#endif
break;
case OPT_LISTEN:
diff --git a/apps/speed.c b/apps/speed.c
index b1732744d3..569f438a39 100644
--- a/apps/speed.c
+++ b/apps/speed.c
@@ -3946,11 +3946,15 @@ int speed_main(int argc, char **argv)
}
if (strncmp(sig_name, "dsa", 3) == 0) {
+ int dsa_nbits = 0;
+
+ if (!opt_int(sig_name + 3, &dsa_nbits))
+ goto sig_err_break;
ctx_params = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
if (ctx_params == NULL
|| EVP_PKEY_paramgen_init(ctx_params) <= 0
|| EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx_params,
- atoi(sig_name + 3))
+ dsa_nbits)
<= 0
|| EVP_PKEY_paramgen(ctx_params, &pkey_params) <= 0
|| (sig_gen_ctx = EVP_PKEY_CTX_new(pkey_params, NULL)) == NULL
diff --git a/crypto/evp/ctrl_params_translate.c b/crypto/evp/ctrl_params_translate.c
index c515c6cbbf..d0529166d7 100644
--- a/crypto/evp/ctrl_params_translate.c
+++ b/crypto/evp/ctrl_params_translate.c
@@ -1046,9 +1046,19 @@ static int fix_dh_nid5114(enum state state,
case PRE_CTRL_STR_TO_PARAMS:
if (ctx->p2 == NULL)
return 0;
- if ((ctx->p2 = (char *)ossl_ffc_named_group_get_name(ossl_ffc_uid_to_dh_named_group(atoi(ctx->p2)))) == NULL) {
- ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE);
- return 0;
+ {
+ int uid;
+
+ if (!ossl_strtoint(ctx->p2, NULL, 10, &uid)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE);
+ return 0;
+ }
+ ctx->p2 = (char *)ossl_ffc_named_group_get_name(
+ ossl_ffc_uid_to_dh_named_group(uid));
+ if (ctx->p2 == NULL) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE);
+ return 0;
+ }
}
ctx->p1 = 0;
@@ -1076,8 +1086,14 @@ static int fix_dh_paramgen_type(enum state state,
return 0;
if (state == PRE_CTRL_STR_TO_PARAMS) {
- if ((ctx->p2 = (char *)ossl_dh_gen_type_id2name(atoi(ctx->p2)))
- == NULL) {
+ int id;
+
+ if (!ossl_strtoint(ctx->p2, NULL, 10, &id)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE);
+ return 0;
+ }
+ ctx->p2 = (char *)ossl_dh_gen_type_id2name(id);
+ if (ctx->p2 == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE);
return 0;
}
@@ -1433,8 +1449,14 @@ static int fix_rsa_pss_saltlen(enum state state,
break;
}
- val = i == OSSL_NELEM(str_value_map) ? atoi(ctx->p2)
- : (int)str_value_map[i].id;
+ if (i == OSSL_NELEM(str_value_map)) {
+ if (!ossl_strtoint(ctx->p2, NULL, 10, &val)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_VALUE);
+ return 0;
+ }
+ } else {
+ val = (int)str_value_map[i].id;
+ }
if (state == POST_CTRL_TO_PARAMS) {
/*
* EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN weirdness explained further
diff --git a/crypto/mem.c b/crypto/mem.c
index 476d6b2529..408c8edfc0 100644
--- a/crypto/mem.c
+++ b/crypto/mem.c
@@ -112,12 +112,19 @@ static void parseit(void)
{
char *semi = strchr(md_failstring, ';');
char *atsign;
+ char *end;
if (semi != NULL)
*semi++ = '\0';
- /* Get the count (atol will stop at the @ if there), and percentage */
- md_count = atol(md_failstring);
+ /*
+ * Get the count (parsing stops at the '@' if present), and percentage.
+ * Ignore an unparsable/overflowing count rather than acting on garbage.
+ * Validate that the count is followed by '@' or end-of-string.
+ */
+ if (!ossl_strtol(md_failstring, &end, 10, &md_count)
+ || (*end != '\0' && *end != '@'))
+ md_count = 0;
atsign = strchr(md_failstring, '@');
md_fail_percent = atsign == NULL ? 0 : (int)(atof(atsign + 1) * 100 + 0.5);
@@ -179,10 +186,19 @@ void ossl_malloc_setup_failures(void)
parseit();
}
}
- if ((cp = getenv("OPENSSL_MALLOC_FD")) != NULL)
- md_tracefd = atoi(cp);
- if ((cp = getenv("OPENSSL_MALLOC_SEED")) != NULL)
- srandom(atoi(cp));
+ if ((cp = getenv("OPENSSL_MALLOC_FD")) != NULL) {
+ int fd;
+
+ if (ossl_strtoint(cp, NULL, 10, &fd) && fd >= 0)
+ md_tracefd = fd;
+ }
+ if ((cp = getenv("OPENSSL_MALLOC_SEED")) != NULL) {
+ unsigned long seed;
+
+ /* Any value is a usable seed; just truncate it to the srandom() type. */
+ if (OPENSSL_strtoul(cp, NULL, 10, &seed))
+ srandom((unsigned int)seed);
+ }
}
#endif
diff --git a/crypto/o_str.c b/crypto/o_str.c
index 2192d48775..d48b43df17 100644
--- a/crypto/o_str.c
+++ b/crypto/o_str.c
@@ -161,6 +161,52 @@ int OPENSSL_strtoul(const char *str, char **endptr, int base,
return 1;
}
+/*
+ * Internal signed counterpart to OPENSSL_strtoul(). Parses a signed long with
+ * the same validation rules: it fails on a conversion error (including
+ * overflow/underflow), if no digits were consumed, or, when |endptr| is NULL,
+ * if the whole string was not consumed. Returns 1 on success (storing the
+ * result in |*result|), 0 otherwise.
+ */
+int ossl_strtol(const char *str, char **endptr, int base, long *result)
+{
+ char *tmp_endptr;
+ char **internal_endptr = endptr == NULL ? &tmp_endptr : endptr;
+
+ errno = 0;
+
+ *internal_endptr = (char *)str;
+
+ if (result == NULL || str == NULL)
+ return 0;
+
+ *result = strtol(str, internal_endptr, base);
+ if (errno != 0
+ || (endptr == NULL && **internal_endptr != '\0')
+ || str == *internal_endptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * As ossl_strtol() but stores the result in an int, additionally failing if
+ * the parsed value does not fit in an int. Returns 1 on success (storing the
+ * result in |*result|), 0 otherwise.
+ */
+int ossl_strtoint(const char *str, char **endptr, int base, int *result)
+{
+ long l;
+
+ if (result == NULL || !ossl_strtol(str, endptr, base, &l))
+ return 0;
+ if (l < INT_MIN || l > INT_MAX)
+ return 0;
+
+ *result = (int)l;
+ return 1;
+}
+
int OPENSSL_hexchar2int(unsigned char c)
{
#ifdef CHARSET_EBCDIC
diff --git a/crypto/ppccap.c b/crypto/ppccap.c
index e029eb3051..189c9e03d4 100644
--- a/crypto/ppccap.c
+++ b/crypto/ppccap.c
@@ -160,11 +160,16 @@ void OPENSSL_cpuid_setup(void)
if (sizeof(size_t) == 4) {
struct utsname uts;
+ long major;
+ char *end;
#if defined(_SC_AIX_KERNEL_BITMODE)
if (sysconf(_SC_AIX_KERNEL_BITMODE) != 64)
return;
#endif
- if (uname(&uts) != 0 || atoi(uts.version) < 6)
+ if (uname(&uts) != 0
+ || !ossl_strtol(uts.version, &end, 10, &major)
+ || (*end != '\0' && *end != '.')
+ || major < 6)
return;
}
diff --git a/crypto/ts/ts_conf.c b/crypto/ts/ts_conf.c
index f8d01813df..1c23eaca89 100644
--- a/crypto/ts/ts_conf.c
+++ b/crypto/ts/ts_conf.c
@@ -358,14 +358,26 @@ int TS_CONF_set_accuracy(CONF *conf, const char *section, TS_RESP_CTX *ctx)
for (i = 0; i < sk_CONF_VALUE_num(list); ++i) {
CONF_VALUE *val = sk_CONF_VALUE_value(list, i);
if (strcmp(val->name, ENV_VALUE_SECS) == 0) {
- if (val->value)
- secs = atoi(val->value);
+ if (val->value != NULL
+ && (!ossl_strtoint(val->value, NULL, 10, &secs)
+ || secs < 0)) {
+ ts_CONF_invalid(section, ENV_ACCURACY);
+ goto err;
+ }
} else if (strcmp(val->name, ENV_VALUE_MILLISECS) == 0) {
- if (val->value)
- millis = atoi(val->value);
+ if (val->value != NULL
+ && (!ossl_strtoint(val->value, NULL, 10, &millis)
+ || millis < 0)) {
+ ts_CONF_invalid(section, ENV_ACCURACY);
+ goto err;
+ }
} else if (strcmp(val->name, ENV_VALUE_MICROSECS) == 0) {
- if (val->value)
- micros = atoi(val->value);
+ if (val->value != NULL
+ && (!ossl_strtoint(val->value, NULL, 10, µs)
+ || micros < 0)) {
+ ts_CONF_invalid(section, ENV_ACCURACY);
+ goto err;
+ }
} else {
ts_CONF_invalid(section, ENV_ACCURACY);
goto err;
diff --git a/demos/digest/EVP_MD_xof.c b/demos/digest/EVP_MD_xof.c
index f0c9de3e5f..d31bd82d12 100644
--- a/demos/digest/EVP_MD_xof.c
+++ b/demos/digest/EVP_MD_xof.c
@@ -9,8 +9,10 @@
#include <stdio.h>
#include <string.h>
+#include <limits.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/crypto.h>
#include <openssl/core_names.h>
/*
@@ -53,7 +55,13 @@ int main(int argc, char **argv)
/* Allow digest length to be changed for demonstration purposes. */
if (argc > 1) {
- digest_len_i = atoi(argv[1]);
+ unsigned long ul;
+
+ if (!OPENSSL_strtoul(argv[1], NULL, 10, &ul) || ul > INT_MAX) {
+ fprintf(stderr, "Specify a non-negative digest length\n");
+ goto end;
+ }
+ digest_len_i = (int)ul;
if (digest_len_i <= 0) {
fprintf(stderr, "Specify a non-negative digest length\n");
goto end;
diff --git a/demos/pkey/EVP_PKEY_RSA_keygen.c b/demos/pkey/EVP_PKEY_RSA_keygen.c
index a889ab6f77..343bc5f296 100644
--- a/demos/pkey/EVP_PKEY_RSA_keygen.c
+++ b/demos/pkey/EVP_PKEY_RSA_keygen.c
@@ -17,8 +17,10 @@
#include <string.h>
#include <stdio.h>
+#include <limits.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include <openssl/crypto.h>
#include <openssl/rsa.h>
#include <openssl/core_names.h>
#include <openssl/pem.h>
@@ -253,7 +255,13 @@ int main(int argc, char **argv)
}
if (argc > 1) {
- bits_i = atoi(argv[1]);
+ unsigned long ul;
+
+ if (!OPENSSL_strtoul(argv[1], NULL, 10, &ul) || ul > INT_MAX) {
+ fprintf(stderr, "Invalid RSA key size\n");
+ return EXIT_FAILURE;
+ }
+ bits_i = (int)ul;
if (bits_i < 512) {
fprintf(stderr, "Invalid RSA key size\n");
return EXIT_FAILURE;
diff --git a/doc/man3/OPENSSL_malloc.pod b/doc/man3/OPENSSL_malloc.pod
index 1907469fcd..a22099ac3e 100644
--- a/doc/man3/OPENSSL_malloc.pod
+++ b/doc/man3/OPENSSL_malloc.pod
@@ -47,7 +47,7 @@ OPENSSL_MALLOC_SEED
char *OPENSSL_strndup(const char *str, size_t s);
size_t OPENSSL_strlcat(char *dst, const char *src, size_t size);
size_t OPENSSL_strlcpy(char *dst, const char *src, size_t size);
- int OPENSSL_strtoul(char *src, char **endptr, int base, unsigned long *num);
+ int OPENSSL_strtoul(const char *str, char **endptr, int base, unsigned long *num);
void *OPENSSL_memdup(void *data, size_t s);
void *OPENSSL_clear_realloc(void *p, size_t old_len, size_t num);
void *OPENSSL_clear_realloc_array(void *p, size_t old_len, size_t num,
@@ -226,8 +226,8 @@ work on all platforms):
...app invocation... 3>/tmp/log$$
If the environment variable B<OPENSSL_MALLOC_SEED> is set, its value
-is interpreted as an integer using atoi(3) and supplied to the srandom(3)
-call for the random number generator initialisation.
+is parsed using OPENSSL_strtoul() and supplied to the srandom(3) call for
+the random number generator initialisation.
=head1 RETURN VALUES
diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h
index 0dcc6b6acd..8bc22e39ce 100644
--- a/include/internal/cryptlib.h
+++ b/include/internal/cryptlib.h
@@ -162,6 +162,19 @@ char *ossl_buf2hexstr_sep(const unsigned char *buf, long buflen, char sep);
unsigned char *ossl_hexstr2buf_sep(const char *str, long *buflen,
const char sep);
+/*
+ * Parse a signed long with validation; see OPENSSL_strtoul() for the rules.
+ * Returns 1 on success (and stores the result in |*result|), 0 on failure.
+ */
+int ossl_strtol(const char *str, char **endptr, int base, long *result);
+
+/*
+ * As ossl_strtol() but stores the result in an int, additionally failing if
+ * the parsed value does not fit in an int.
+ * Returns 1 on success (and stores the result in |*result|), 0 on failure.
+ */
+int ossl_strtoint(const char *str, char **endptr, int base, int *result);
+
/**
* Writes |n| value in hex format into |buf|,
* and returns the number of bytes written
diff --git a/providers/implementations/rands/seeding/rand_unix.c b/providers/implementations/rands/seeding/rand_unix.c
index 67b38cb719..d1bda5c68e 100644
--- a/providers/implementations/rands/seeding/rand_unix.c
+++ b/providers/implementations/rands/seeding/rand_unix.c
@@ -451,9 +451,19 @@ static int wait_random_seeded(void)
* this alternative but essentially identical source moot.
*/
if (uname(&un) == 0) {
- kernel[0] = atoi(un.release);
+ int val;
+ char *end;
+
+ kernel[0] = (ossl_strtoint(un.release, &end, 10, &val)
+ && (*end == '.' || *end == '\0'))
+ ? val
+ : 0;
p = strchr(un.release, '.');
- kernel[1] = p == NULL ? 0 : atoi(p + 1);
+ kernel[1] = (p != NULL
+ && ossl_strtoint(p + 1, &end, 10, &val)
+ && (*end == '.' || *end == '\0'))
+ ? val
+ : 0;
if (kernel[0] > kernel_version[0]
|| (kernel[0] == kernel_version[0]
&& kernel[1] >= kernel_version[1])) {
diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c
index 232414935f..7b35fec028 100644
--- a/providers/implementations/signature/rsa_sig.c
+++ b/providers/implementations/signature/rsa_sig.c
@@ -1695,8 +1695,11 @@ static int rsa_set_ctx_params(void *vprsactx, const OSSL_PARAM params[])
saltlen = RSA_PSS_SALTLEN_AUTO;
else if (strcmp(p.slen->data, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX) == 0)
saltlen = RSA_PSS_SALTLEN_AUTO_DIGEST_MAX;
- else
- saltlen = atoi(p.slen->data);
+ else if (!ossl_strtoint(p.slen->data, NULL, 10, &saltlen)) {
+ ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_SALT_LENGTH,
+ "invalid RSA-PSS saltlen value");
+ return 0;
+ }
}
/*
diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c
index a7293512b9..d065b649d5 100644
--- a/ssl/ssl_conf.c
+++ b/ssl/ssl_conf.c
@@ -9,6 +9,7 @@
#include "internal/e_os.h"
+#include <limits.h>
#include <stdio.h>
#include "ssl_local.h"
#include <openssl/conf.h>
@@ -723,9 +724,11 @@ out:
static int cmd_NumTickets(SSL_CONF_CTX *cctx, const char *value)
{
int rv = 0;
- int num_tickets = atoi(value);
+ unsigned long ul;
+
+ if (OPENSSL_strtoul(value, NULL, 10, &ul) && ul <= INT_MAX) {
+ int num_tickets = (int)ul;
- if (num_tickets >= 0) {
if (cctx->ctx)
rv = SSL_CTX_set_num_tickets(cctx->ctx, num_tickets);
if (cctx->ssl)
diff --git a/test/evp_test.c b/test/evp_test.c
index 77029f40db..ef6dea9664 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -475,10 +475,9 @@ static int evp_test_buffer_ncopy(const char *value,
EVP_TEST_BUFFER *db;
unsigned char *tbuf, *p;
size_t tbuflen;
- int ncopy = atoi(value);
- int i;
+ int ncopy = 0, i;
- if (ncopy <= 0)
+ if (!test_strtoint(value, &ncopy) || ncopy <= 0)
return 0;
if (sk == NULL || sk_EVP_TEST_BUFFER_num(sk) == 0)
return 0;
@@ -501,9 +500,9 @@ static int evp_test_buffer_set_count(const char *value,
STACK_OF(EVP_TEST_BUFFER) *sk)
{
EVP_TEST_BUFFER *db;
- int count = atoi(value);
+ int count = 0;
- if (count <= 0)
+ if (!test_strtoint(value, &count) || count <= 0)
return 0;
if (sk == NULL || sk_EVP_TEST_BUFFER_num(sk) == 0)
@@ -764,14 +763,13 @@ static int digest_test_parse(EVP_TEST *t,
if (strcmp(keyword, "Ncopy") == 0)
return evp_test_buffer_ncopy(value, mdata->input);
if (strcmp(keyword, "Padding") == 0)
- return (mdata->pad_type = atoi(value)) > 0;
+ return test_strtoint(value, &mdata->pad_type) && mdata->pad_type > 0;
if (strcmp(keyword, "XOF") == 0)
- return (mdata->xof = atoi(value)) > 0;
+ return test_strtoint(value, &mdata->xof) && mdata->xof > 0;
if (strcmp(keyword, "OutputSize") == 0) {
int sz;
- sz = atoi(value);
- if (sz < 0)
+ if (!test_strtoint(value, &sz))
return -1;
mdata->digest_size = sz;
return 1;
@@ -1065,8 +1063,7 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword,
if (strcmp(keyword, "Key") == 0)
return parse_bin(value, &cdat->key, &cdat->key_len);
if (strcmp(keyword, "Rounds") == 0) {
- i = atoi(value);
- if (i < 0)
+ if (!test_strtoint(value, &i))
return -1;
cdat->rounds = (unsigned int)i;
return 1;
@@ -1080,8 +1077,7 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword,
if (strcmp(keyword, "Ciphertext") == 0)
return parse_bin(value, &cdat->ciphertext, &cdat->ciphertext_len);
if (strcmp(keyword, "KeyBits") == 0) {
- i = atoi(value);
- if (i < 0)
+ if (!test_strtoint(value, &i))
return -1;
cdat->key_bits = (size_t)i;
return 1;
@@ -1838,14 +1834,12 @@ static int mac_test_parse(EVP_TEST *t,
if (strcmp(keyword, "Ctrl") == 0)
return ctrladd(mdata->controls, value);
if (strcmp(keyword, "OutputSize") == 0) {
- mdata->output_size = atoi(value);
- if (mdata->output_size < 0)
+ if (!test_strtoint(value, &mdata->output_size))
return -1;
return 1;
}
if (strcmp(keyword, "BlockSize") == 0) {
- mdata->block_size = atoi(value);
- if (mdata->block_size < 0)
+ if (!test_strtoint(value, &mdata->block_size))
return -1;
return 1;
}
@@ -3451,8 +3445,7 @@ static int pbkdf2_test_parse(EVP_TEST *t,
PBE_DATA *pdata = t->data;
if (strcmp(keyword, "iter") == 0) {
- pdata->iter = atoi(value);
- if (pdata->iter <= 0)
+ if (!test_strtoint(value, &pdata->iter) || pdata->iter <= 0)
return -1;
return 1;
}
@@ -3471,8 +3464,7 @@ static int pkcs12_test_parse(EVP_TEST *t,
PBE_DATA *pdata = t->data;
if (strcmp(keyword, "id") == 0) {
- pdata->id = atoi(value);
- if (pdata->id <= 0)
+ if (!test_strtoint(value, &pdata->id) || pdata->id <= 0)
return -1;
return 1;
}
@@ -3901,7 +3893,8 @@ static int rand_test_parse(EVP_TEST *t,
int n;
if ((p = strchr(keyword, '.')) != NULL) {
- n = atoi(++p);
+ if (!test_strtoint(++p, &n))
+ return 0;
if (n >= MAX_RAND_REPEATS)
return 0;
if (n > rdata->n)
@@ -3935,17 +3928,21 @@ static int rand_test_parse(EVP_TEST *t,
if (strcmp(keyword, "Digest") == 0)
return TEST_ptr(rdata->digest = OPENSSL_strdup(value));
if (strcmp(keyword, "DerivationFunction") == 0) {
- rdata->use_df = atoi(value) != 0;
+ n = 0;
+ (void)test_strtoint(value, &n);
+ rdata->use_df = n != 0;
return 1;
}
if (strcmp(keyword, "GenerateBits") == 0) {
- if ((n = atoi(value)) <= 0 || n % 8 != 0)
+ if (!test_strtoint(value, &n) || n <= 0 || n % 8 != 0)
return 0;
rdata->generate_bits = (unsigned int)n;
return 1;
}
if (strcmp(keyword, "PredictionResistance") == 0) {
- rdata->prediction_resistance = atoi(value) != 0;
+ n = 0;
+ (void)test_strtoint(value, &n);
+ rdata->prediction_resistance = n != 0;
return 1;
}
if (strcmp(keyword, "CtrlInit") == 0)
@@ -5612,7 +5609,10 @@ start:
}
t->reason = take_value(pp);
} else if (strcmp(pp->key, "Threads") == 0) {
- if (OSSL_set_max_threads(libctx, atoi(pp->value)) == 0) {
+ int nthreads = 0;
+
+ (void)test_strtoint(pp->value, &nthreads);
+ if (OSSL_set_max_threads(libctx, nthreads) == 0) {
TEST_info("skipping, '%s' threads not available: %s:%d",
pp->value, t->s.test_file, t->s.start);
t->skip = 1;
@@ -5630,8 +5630,9 @@ start:
TEST_info("Line %d: multiple security category lines", t->s.curr);
return 0;
}
- t->security_category = atoi(pp->value);
- if (t->security_category < 0 || t->security_category > 5) {
+ t->security_category = 0;
+ if (!test_strtoint(pp->value, &t->security_category)
+ || t->security_category > 5) {
TEST_info("Line %d: invalid security category, should be 0..5",
t->s.curr);
return 0;
diff --git a/test/helpers/ssl_test_ctx.c b/test/helpers/ssl_test_ctx.c
index 321d1a378a..f8b88df861 100644
--- a/test/helpers/ssl_test_ctx.c
+++ b/test/helpers/ssl_test_ctx.c
@@ -56,7 +56,8 @@ static int parse_boolean(const char *value, int *result)
#define IMPLEMENT_SSL_TEST_INT_OPTION(struct_type, name, field) \
static int parse_##name##_##field(struct_type *ctx, const char *value) \
{ \
- ctx->field = atoi(value); \
+ if (!test_strtoint(value, &ctx->field)) \
+ ctx->field = 0; \
return 1; \
}
diff --git a/test/lhash_test.c b/test/lhash_test.c
index 87dc71f829..394321151f 100644
--- a/test/lhash_test.c
+++ b/test/lhash_test.c
@@ -590,14 +590,16 @@ static int setup_num_workers(void)
char *lhash_workers = getenv("LHASH_WORKERS");
/* If we have HARNESS_JOBS set, don't eat more than a quarter */
if (harness_jobs != NULL) {
- int jobs = atoi(harness_jobs);
- if (jobs > 0)
+ int jobs;
+
+ if (test_strtoint(harness_jobs, &jobs) && jobs > 0)
num_workers = jobs / 4;
}
/* But if we have explicitly set LHASH_WORKERS use that */
if (lhash_workers != NULL) {
- int jobs = atoi(lhash_workers);
- if (jobs > 0)
+ int jobs;
+
+ if (test_strtoint(lhash_workers, &jobs) && jobs > 0)
num_workers = jobs;
}
diff --git a/test/mfail/mfail.c b/test/mfail/mfail.c
index ec391c8e85..70f575afc9 100644
--- a/test/mfail/mfail.c
+++ b/test/mfail/mfail.c
@@ -12,6 +12,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <openssl/crypto.h>
#if defined(__has_feature)
@@ -69,7 +70,12 @@ static int env_is_true(const char *name)
static int env_int(const char *name, int dflt)
{
const char *value = getenv(name);
- return (value != NULL && *value != '\0') ? atoi(value) : dflt;
+ unsigned long ul;
+
+ if (value != NULL && *value != '\0'
+ && OPENSSL_strtoul(value, NULL, 10, &ul) && ul <= INT_MAX)
+ return (int)ul;
+ return dflt;
}
static void mfail_print_bt(void)
diff --git a/test/recipes/30-test_evp_data/evppkey_rsa_common.txt b/test/recipes/30-test_evp_data/evppkey_rsa_common.txt
index e97ff64c09..58ac329afe 100644
--- a/test/recipes/30-test_evp_data/evppkey_rsa_common.txt
+++ b/test/recipes/30-test_evp_data/evppkey_rsa_common.txt
@@ -966,6 +966,12 @@ Input="0123456789ABCDEF0123456789ABCDEF"
Output=4DE433D5844043EF08D354DA03CB29068780D52706D7D1E4D50EFB7D58C9D547D83A747DDD0635A96B28F854E50145518482CB49E963054621B53C60C498D07C16E9C2789C893CF38D4D86900DE71BDE463BD2761D1271E358C7480A1AC0BAB930DDF39602AD1BC165B5D7436B516B7A7858E8EB7AB1C420EEB482F4D207F0E462B1724959320A084E13848D11D10FB593E66BF680BF6D3F345FC3E9C3DE60ABBAC37E1C6EC80A268C8D9FC49626C679097AA690BC1AA662B95EB8DB70390861AA0898229F9349B4B5FDD030D4928C47084708A933144BE23BD3C6E661B85B2C0EF9ED36D498D5B7320E8194D363D4AD478C059BAE804181965E0B81B663158A
Result = VERIFY_ERROR
+# Invalid numeric salt length string
+Verify = RSA-2048-PUBLIC
+Ctrl = rsa_padding_mode:pss
+Ctrl = rsa_pss_saltlen:1x
+Result = PKEY_CTRL_ERROR
+
# Verify using default parameters, explicitly setting parameters
Verify = RSA-PSS-DEFAULT
Ctrl = rsa_padding_mode:pss
diff --git a/test/ssl_old_test.c b/test/ssl_old_test.c
index 40df6536e3..48e3f61cf3 100644
--- a/test/ssl_old_test.c
+++ b/test/ssl_old_test.c
@@ -1043,13 +1043,16 @@ int main(int argc, char *argv[])
} else if (HAS_PREFIX(*argv, "-num")) {
if (--argc < 1)
goto bad;
- number = atoi(*(++argv));
+ (void)test_strtoint(*(++argv), &number);
if (number == 0)
number = 1;
} else if (strcmp(*argv, "-bytes") == 0) {
+ unsigned long ul = 0;
+
if (--argc < 1)
goto bad;
- bytes = atol(*(++argv));
+ if (OPENSSL_strtoul(*(++argv), NULL, 10, &ul) && ul <= LONG_MAX)
+ bytes = (long)ul;
if (bytes == 0L)
bytes = 1L;
i = (int)strlen(argv[0]);
@@ -1191,9 +1194,12 @@ int main(int argc, char *argv[])
goto bad;
client_sess_in = *(++argv);
} else if (strcmp(*argv, "-should_reuse") == 0) {
+ int reuse_arg = 0;
+
if (--argc < 1)
goto bad;
- should_reuse = !!atoi(*(++argv));
+ (void)test_strtoint(*(++argv), &reuse_arg);
+ should_reuse = reuse_arg != 0;
} else if (strcmp(*argv, "-no_ticket") == 0) {
no_ticket = 1;
} else if (strcmp(*argv, "-client_ktls") == 0) {
diff --git a/test/testutil.h b/test/testutil.h
index 7e23f53827..cda7716cdf 100644
--- a/test/testutil.h
+++ b/test/testutil.h
@@ -712,6 +712,14 @@ STACK_OF(X509) *load_certs_pem(const char *file);
X509_REQ *load_csr_der(const char *file, OSSL_LIB_CTX *libctx);
int test_asn1_string_to_time_t(const char *asn1_string, time_t *out_time_t);
int compare_with_reference_file(BIO *membio, const char *reffile);
+
+/*
+ * Parse a non-negative decimal integer from |value| into |*result|. Returns 1
+ * on success, 0 on failure (NULL/empty/non-numeric/negative/overflowing input,
+ * or trailing garbage). Test binaries link only against the public ABI, so
+ * this wraps OPENSSL_strtoul() rather than the libcrypto-internal helpers.
+ */
+int test_strtoint(const char *value, int *result);
/*
* Create an X509 from an array of strings.
*/
diff --git a/test/testutil/driver.c b/test/testutil/driver.c
index bfcb65b7bc..8e3637acfe 100644
--- a/test/testutil/driver.c
+++ b/test/testutil/driver.c
@@ -13,6 +13,7 @@
#include <string.h>
#include <assert.h>
+#include <limits.h>
#include "internal/nelem.h"
#include <openssl/bio.h>
@@ -138,14 +139,22 @@ int setup_test_framework(int argc, char *argv[])
char *test_rand_seed = getenv("OPENSSL_TEST_RAND_SEED");
char *TAP_levels = getenv("HARNESS_OSSL_LEVEL");
- if (TAP_levels != NULL)
- level = 4 * atoi(TAP_levels);
+ if (TAP_levels != NULL) {
+ int n;
+
+ if (test_strtoint(TAP_levels, &n) && n <= INT_MAX / 4)
+ level = 4 * n;
+ }
test_adjust_streams_tap_level(level);
if (test_rand_order != NULL) {
+ int n;
+
rand_order = 1;
- set_seed(atoi(test_rand_order));
+ set_seed(test_strtoint(test_rand_order, &n) ? n : 0);
} else if (test_rand_seed != NULL) {
- set_seed(atoi(test_rand_seed));
+ int n;
+
+ set_seed(test_strtoint(test_rand_seed, &n) ? n : 0);
} else {
set_seed(0);
}
@@ -178,8 +187,12 @@ static int check_single_test_params(char *name, char *testname, char *itname)
break;
}
}
- if (i >= num_tests)
- single_test = atoi(name);
+ if (i >= num_tests) {
+ int n;
+
+ if (test_strtoint(name, &n))
+ single_test = n;
+ }
}
/* if only iteration is specified, assume we want the first test */
diff --git a/test/testutil/helper.c b/test/testutil/helper.c
index 551b9a200b..a23e8c2f23 100644
--- a/test/testutil/helper.c
+++ b/test/testutil/helper.c
@@ -7,12 +7,24 @@
* https://www.openssl.org/source/license.html
*/
#include <time.h>
+#include <limits.h>
#include <openssl/asn1t.h>
#include <openssl/posix_time.h>
+#include <openssl/crypto.h>
#include "../testutil.h"
+int test_strtoint(const char *value, int *result)
+{
+ unsigned long ul;
+
+ if (!OPENSSL_strtoul(value, NULL, 10, &ul) || ul > INT_MAX)
+ return 0;
+ *result = (int)ul;
+ return 1;
+}
+
int test_asn1_string_to_time_t(const char *asn1_string, time_t *out_time_t)
{
int ret = 0;
diff --git a/test/timing_load_creds.c b/test/timing_load_creds.c
index 5e9e2bf6c0..45cdc2e1da 100644
--- a/test/timing_load_creds.c
+++ b/test/timing_load_creds.c
@@ -9,8 +9,10 @@
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#include <openssl/e_os2.h>
+#include <openssl/crypto.h>
#ifdef OPENSSL_SYS_UNIX
#include <sys/stat.h>
@@ -120,10 +122,14 @@ int main(int ac, char **av)
default:
usage();
break;
- case 'c':
- if ((count = atoi(optarg)) < 0)
+ case 'c': {
+ unsigned long ul;
+
+ if (!OPENSSL_strtoul(optarg, NULL, 10, &ul) || ul > INT_MAX)
usage();
+ count = (int)ul;
break;
+ }
case 'd':
debug = 1;
break;
diff --git a/util/platform_symbols/unix-symbols.txt b/util/platform_symbols/unix-symbols.txt
index 62720f35fd..bfd60a51b7 100644
--- a/util/platform_symbols/unix-symbols.txt
+++ b/util/platform_symbols/unix-symbols.txt
@@ -1,7 +1,6 @@
abort
accept
aligned_alloc
-atoi
bcmp
bind
calloc
diff --git a/util/platform_symbols/windows-symbols.txt b/util/platform_symbols/windows-symbols.txt
index 7ae58a3f18..cd41c7ec02 100644
--- a/util/platform_symbols/windows-symbols.txt
+++ b/util/platform_symbols/windows-symbols.txt
@@ -125,7 +125,6 @@ _stat64i32
_strdup
_time64
_wfopen
-atoi
calloc
clearerr
fclose