]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add an OPENSSL_strtoul wrapper
authorNeil Horman <nhorman@openssl.org>
Fri, 12 Jul 2024 14:46:23 +0000 (10:46 -0400)
committerTomas Mraz <tomas@openssl.org>
Thu, 18 Jul 2024 17:07:52 +0000 (19:07 +0200)
utility function to give us sane checking on strtoul conversions

Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24861)

crypto/o_str.c
doc/man3/OPENSSL_malloc.pod
include/openssl/crypto.h.in
util/libcrypto.num

index dfac215ac35624d1c3ccb51121e4cae537dfb710..ba41d76fc17212fa594f62dc2b03da36a3b65569 100644 (file)
@@ -90,6 +90,74 @@ size_t OPENSSL_strlcat(char *dst, const char *src, size_t size)
     return l + OPENSSL_strlcpy(dst, src, size);
 }
 
+/**
+ * @brief Converts a string to an unsigned long integer.
+ *
+ * This function attempts to convert a string representation of a number
+ * to an unsigned long integer, given a specified base. It also provides
+ * error checking and reports whether the conversion was successful.
+ * This function is just a wrapper around the POSIX strtoul function with
+ * additional error checking.  This implies that errno for the caller is set
+ * on calls to this function.
+ *
+ * @param str The string containing the representation of the number.
+ * @param endptr A pointer to a pointer to character. If not NULL, it is set
+ *               to the character immediately following the number in the
+ *               string.
+ * @param base The base to use for the conversion, which must be between 2,
+ *             and 36 inclusive, or be the special value 0. If the base is 0,
+ *             the actual base is determined by the format of the initial
+ *             characters of the string.
+ * @param num A pointer to an unsigned long where the result of the
+ *            conversion is stored.
+ *
+ * @return 1 if the conversion was successful, 0 otherwise. Conversion is
+ *         considered unsuccessful if no digits were consumed or if an error
+ *         occurred during conversion.
+ *
+ * @note It is the caller's responsibility to check if the conversion is
+ *       correct based on the expected consumption of the string as reported
+ *       by endptr.
+ */
+int OPENSSL_strtoul(const char *str, char **endptr, int base,
+                    unsigned long *num)
+{
+    char *tmp_endptr;
+    char **internal_endptr = endptr == NULL ? &tmp_endptr : endptr;
+
+    errno = 0;
+
+    *internal_endptr = (char *)str;
+
+    if (num == NULL)
+        return 0;
+
+    if (str == NULL)
+        return 0;
+
+    /* Fail on negative input */
+    if (*str == '-')
+        return 0;
+
+    *num = strtoul(str, internal_endptr, base);
+    /*
+     * We return error from this function under the following conditions
+     * 1) If strtoul itself returned an error in translation
+     * 2) If the caller didn't pass in an endptr value, and **internal_endptr
+     *    doesn't point to '\0'.  The implication here is that if the caller
+     *    doesn't care how much of a string is consumed, they expect the entire
+     *    string to be consumed.  As such, no pointing to the NULL terminator
+     *    means there was some part of the string left over after translation
+     * 3) If no bytes of the string were consumed
+     */
+    if (errno != 0 ||
+        (endptr == NULL && **internal_endptr != '\0') ||
+        (str == *internal_endptr))
+        return 0;
+
+    return 1;
+}
+
 int OPENSSL_hexchar2int(unsigned char c)
 {
 #ifdef CHARSET_EBCDIC
index 3c4099bc8596217609a33f12f1a1e5e3d433b944..6d9251ec3b29b4795f446daa46aff8d847eaf08e 100644 (file)
@@ -7,7 +7,7 @@ OPENSSL_malloc, OPENSSL_aligned_alloc, OPENSSL_zalloc, OPENSSL_realloc,
 OPENSSL_free, OPENSSL_clear_realloc, OPENSSL_clear_free, OPENSSL_cleanse,
 CRYPTO_malloc, CRYPTO_aligned_alloc, CRYPTO_zalloc, CRYPTO_realloc, CRYPTO_free,
 OPENSSL_strdup, OPENSSL_strndup,
-OPENSSL_memdup, OPENSSL_strlcpy, OPENSSL_strlcat,
+OPENSSL_memdup, OPENSSL_strlcpy, OPENSSL_strlcat, OPENSSL_strtoul,
 CRYPTO_strdup, CRYPTO_strndup,
 OPENSSL_mem_debug_push, OPENSSL_mem_debug_pop,
 CRYPTO_mem_debug_push, CRYPTO_mem_debug_pop,
@@ -36,6 +36,7 @@ OPENSSL_MALLOC_FD
  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);
  void *OPENSSL_memdup(void *data, size_t s);
  void *OPENSSL_clear_realloc(void *p, size_t old_len, size_t num);
  void OPENSSL_clear_free(void *str, size_t num);
@@ -135,6 +136,12 @@ OPENSSL_strlcpy(),
 OPENSSL_strlcat() and OPENSSL_strnlen() are equivalents of the common C
 library functions and are provided for portability.
 
+OPENSSL_strtoul() is a wrapper around the POSIX function strtoul, with the same
+behaviors listed in the POSIX documentation, with the additional behavior that
+it validates the input I<str> and I<num> parameters for not being NULL, and confirms
+that at least a single byte of input has been consumed in the translation,
+returning an error in the event that no bytes were consumed.
+
 If no allocations have been done, it is possible to "swap out" the default
 implementations for OPENSSL_malloc(), OPENSSL_realloc() and OPENSSL_free()
 and replace them with alternate versions.
@@ -203,6 +210,35 @@ OPENSSL_mem_debug_push(), OPENSSL_mem_debug_pop(),
 CRYPTO_mem_debug_push(), and CRYPTO_mem_debug_pop()
 are deprecated and are no-ops that always return 0.
 
+OPENSSL_strtoul() returns 1 on success and 0 in the event that an error has
+occured. Specifically, 0 is returned in the following events:
+
+=over 4
+
+=item *
+
+If the underlying call to strtoul returned a non zero errno value
+
+=item *
+
+If the translation did not consume the entire input string, and the passed
+endptr value was NULL
+
+=item *
+
+If no characters were consumed in the translation
+
+=back
+
+Note that a success condition does not imply that the expected
+translation has been preformed.  For instance calling
+
+    OPENSSL_strtoul("0x12345", &endptr, 10, &num);
+
+will result in a successful translation with num having the value 0, and
+*endptr = 'x'.  Be sure to validate how much data was consumed when calling this
+function.
+
 =head1 HISTORY
 
 OPENSSL_mem_debug_push(), OPENSSL_mem_debug_pop(),
index 99041cce065e209b5a1b1332fd9bfbd23e963433..11a9ec9a24f26e42e99d7c2ff86f613387b345ca 100644 (file)
@@ -134,6 +134,7 @@ int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock);
 size_t OPENSSL_strlcpy(char *dst, const char *src, size_t siz);
 size_t OPENSSL_strlcat(char *dst, const char *src, size_t siz);
 size_t OPENSSL_strnlen(const char *str, size_t maxlen);
+int OPENSSL_strtoul(const char *str, char **endptr, int base, unsigned long *num);
 int OPENSSL_buf2hexstr_ex(char *str, size_t str_n, size_t *strlength,
                           const unsigned char *buf, size_t buflen,
                           const char sep);
index e434b95d4603903c7d77191538da87f5dc4a72a2..295f96bded47eeaf30ff32864b254d1f19b95e7b 100644 (file)
@@ -5702,3 +5702,4 @@ OSSL_USER_NOTICE_SYNTAX_new             ? 3_4_0   EXIST::FUNCTION:
 OSSL_USER_NOTICE_SYNTAX_it              ?      3_4_0   EXIST::FUNCTION:
 OSSL_INDICATOR_set_callback             ?      3_4_0   EXIST::FUNCTION:
 OSSL_INDICATOR_get_callback             ?      3_4_0   EXIST::FUNCTION:
+OPENSSL_strtoul                         ?      3_4_0   EXIST::FUNCTION: