mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Add zend_random_bytes(), zend_random_bytes_insecure() functions (#14054)
Co-authored-by: Tim Düsterhus <tim@bastelstu.be>
This commit is contained in:
parent
d545b1d643
commit
d1048a0869
10 changed files with 169 additions and 12 deletions
|
@ -94,6 +94,8 @@ ZEND_API char *(*zend_getenv)(const char *name, size_t name_len);
|
|||
ZEND_API zend_string *(*zend_resolve_path)(zend_string *filename);
|
||||
ZEND_API zend_result (*zend_post_startup_cb)(void) = NULL;
|
||||
ZEND_API void (*zend_post_shutdown_cb)(void) = NULL;
|
||||
ZEND_ATTRIBUTE_NONNULL ZEND_API zend_result (*zend_random_bytes)(void *bytes, size_t size, char *errstr, size_t errstr_size) = NULL;
|
||||
ZEND_ATTRIBUTE_NONNULL ZEND_API void (*zend_random_bytes_insecure)(zend_random_bytes_insecure_state *state, void *bytes, size_t size) = NULL;
|
||||
|
||||
/* This callback must be signal handler safe! */
|
||||
void (*zend_on_timeout)(int seconds);
|
||||
|
@ -912,6 +914,10 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
|
|||
php_win32_cp_set_by_id(65001);
|
||||
#endif
|
||||
|
||||
/* Set up early utility functions. */
|
||||
zend_random_bytes = utility_functions->random_bytes_function;
|
||||
zend_random_bytes_insecure = utility_functions->random_bytes_insecure_function;
|
||||
|
||||
start_memory_manager();
|
||||
|
||||
virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */
|
||||
|
|
15
Zend/zend.h
15
Zend/zend.h
|
@ -234,6 +234,11 @@ struct _zend_class_entry {
|
|||
} info;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
zend_max_align_t align;
|
||||
uint64_t opaque[5];
|
||||
} zend_random_bytes_insecure_state;
|
||||
|
||||
typedef struct _zend_utility_functions {
|
||||
void (*error_function)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message);
|
||||
size_t (*printf_function)(const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 1, 2);
|
||||
|
@ -248,6 +253,8 @@ typedef struct _zend_utility_functions {
|
|||
void (*printf_to_smart_str_function)(smart_str *buf, const char *format, va_list ap);
|
||||
char *(*getenv_function)(const char *name, size_t name_len);
|
||||
zend_string *(*resolve_path_function)(zend_string *filename);
|
||||
zend_result (*random_bytes_function)(void *bytes, size_t size, char *errstr, size_t errstr_size);
|
||||
void (*random_bytes_insecure_function)(zend_random_bytes_insecure_state *state, void *bytes, size_t size);
|
||||
} zend_utility_functions;
|
||||
|
||||
typedef struct _zend_utility_values {
|
||||
|
@ -340,6 +347,14 @@ extern void (*zend_printf_to_smart_string)(smart_string *buf, const char *format
|
|||
extern void (*zend_printf_to_smart_str)(smart_str *buf, const char *format, va_list ap);
|
||||
extern ZEND_API char *(*zend_getenv)(const char *name, size_t name_len);
|
||||
extern ZEND_API zend_string *(*zend_resolve_path)(zend_string *filename);
|
||||
/* Generate 'size' random bytes into 'bytes' with the OS CSPRNG. */
|
||||
extern ZEND_ATTRIBUTE_NONNULL ZEND_API zend_result (*zend_random_bytes)(
|
||||
void *bytes, size_t size, char *errstr, size_t errstr_size);
|
||||
/* Generate 'size' random bytes into 'bytes' with a general purpose PRNG (not
|
||||
* crypto safe). 'state' must be zeroed before the first call and can be reused.
|
||||
*/
|
||||
extern ZEND_ATTRIBUTE_NONNULL ZEND_API void (*zend_random_bytes_insecure)(
|
||||
zend_random_bytes_insecure_state *state, void *bytes, size_t size);
|
||||
|
||||
/* These two callbacks are especially for opcache */
|
||||
extern ZEND_API zend_result (*zend_post_startup_cb)(void);
|
||||
|
|
|
@ -791,4 +791,24 @@ extern "C++" {
|
|||
# define ZEND_STATIC_ASSERT(c, m)
|
||||
#endif
|
||||
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) /* C11 */ \
|
||||
|| (defined(__cplusplus) && __cplusplus >= 201103L) /* C++11 */
|
||||
typedef max_align_t zend_max_align_t;
|
||||
#else
|
||||
typedef union {
|
||||
char c;
|
||||
short s;
|
||||
int i;
|
||||
long l;
|
||||
#if SIZEOF_LONG_LONG
|
||||
long long ll;
|
||||
#endif
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
void *p;
|
||||
void (*fun)();
|
||||
} zend_max_align_t;
|
||||
#endif
|
||||
|
||||
#endif /* ZEND_PORTABILITY_H */
|
||||
|
|
|
@ -27,6 +27,7 @@ PHP_NEW_EXTENSION(random,
|
|||
engine_secure.c \
|
||||
engine_user.c \
|
||||
gammasection.c \
|
||||
randomizer.c,
|
||||
randomizer.c \
|
||||
zend_utils.c,
|
||||
no,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
||||
PHP_INSTALL_HEADERS([ext/random], [php_random.h php_random_csprng.h php_random_uint128.h])
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
EXTENSION("random", "random.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
PHP_RANDOM="yes";
|
||||
ADD_SOURCES(configure_module_dirname, "csprng.c engine_combinedlcg.c engine_mt19937.c engine_pcgoneseq128xslrr64.c engine_xoshiro256starstar.c engine_secure.c engine_user.c gammasection.c randomizer.c", "random");
|
||||
ADD_SOURCES(configure_module_dirname, "csprng.c engine_combinedlcg.c engine_mt19937.c engine_pcgoneseq128xslrr64.c engine_xoshiro256starstar.c engine_secure.c engine_user.c gammasection.c randomizer.c zend_utils.c", "random");
|
||||
PHP_INSTALL_HEADERS("ext/random", "php_random.h php_random_csprng.h php_random_uint128.h");
|
||||
|
|
|
@ -37,7 +37,10 @@
|
|||
|
||||
PHPAPI double php_combined_lcg(void);
|
||||
|
||||
typedef struct _php_random_fallback_seed_state php_random_fallback_seed_state;
|
||||
|
||||
PHPAPI uint64_t php_random_generate_fallback_seed(void);
|
||||
PHPAPI uint64_t php_random_generate_fallback_seed_ex(php_random_fallback_seed_state *state);
|
||||
|
||||
static inline zend_long GENERATE_SEED(void)
|
||||
{
|
||||
|
@ -99,6 +102,11 @@ typedef struct _php_random_algo_with_state {
|
|||
void *state;
|
||||
} php_random_algo_with_state;
|
||||
|
||||
typedef struct _php_random_fallback_seed_state {
|
||||
bool initialized;
|
||||
unsigned char seed[20];
|
||||
} php_random_fallback_seed_state;
|
||||
|
||||
extern PHPAPI const php_random_algo php_random_algo_combinedlcg;
|
||||
extern PHPAPI const php_random_algo php_random_algo_mt19937;
|
||||
extern PHPAPI const php_random_algo php_random_algo_pcgoneseq128xslrr64;
|
||||
|
@ -197,8 +205,7 @@ PHP_RINIT_FUNCTION(random);
|
|||
ZEND_BEGIN_MODULE_GLOBALS(random)
|
||||
bool combined_lcg_seeded;
|
||||
bool mt19937_seeded;
|
||||
bool fallback_seed_initialized;
|
||||
unsigned char fallback_seed[20];
|
||||
php_random_fallback_seed_state fallback_seed_state;
|
||||
php_random_status_state_combinedlcg combined_lcg;
|
||||
php_random_status_state_mt19937 mt19937;
|
||||
ZEND_END_MODULE_GLOBALS(random)
|
||||
|
|
35
ext/random/php_random_zend_utils.h
Normal file
35
ext/random/php_random_zend_utils.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Arnaud Le Blanc <arnaud.lb@gmail.com> |
|
||||
| Tim Düsterhus <timwolla@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef PHP_RANDOM_ZEND_UTILS_H
|
||||
# define PHP_RANDOM_ZEND_UTILS_H
|
||||
|
||||
# include "php.h"
|
||||
# include "php_random.h"
|
||||
# include "zend.h"
|
||||
|
||||
typedef struct _php_random_bytes_insecure_state_for_zend {
|
||||
bool initialized;
|
||||
php_random_status_state_xoshiro256starstar xoshiro256starstar_state;
|
||||
} php_random_bytes_insecure_state_for_zend;
|
||||
|
||||
ZEND_STATIC_ASSERT(sizeof(zend_random_bytes_insecure_state) >= sizeof(php_random_bytes_insecure_state_for_zend), "");
|
||||
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_random_bytes_insecure_for_zend(
|
||||
zend_random_bytes_insecure_state *state, void *bytes, size_t size);
|
||||
|
||||
#endif /* PHP_RANDOM_ZEND_UTILS_H */
|
|
@ -610,7 +610,7 @@ static inline void fallback_seed_add(PHP_SHA1_CTX *c, void *p, size_t l){
|
|||
PHP_SHA1Update(c, p, l);
|
||||
}
|
||||
|
||||
PHPAPI uint64_t php_random_generate_fallback_seed(void)
|
||||
PHPAPI uint64_t php_random_generate_fallback_seed_ex(php_random_fallback_seed_state *state)
|
||||
{
|
||||
/* Mix various values using SHA-1 as a PRF to obtain as
|
||||
* much entropy as possible, hopefully generating an
|
||||
|
@ -628,7 +628,7 @@ PHPAPI uint64_t php_random_generate_fallback_seed(void)
|
|||
char buf[64 + 1];
|
||||
|
||||
PHP_SHA1Init(&c);
|
||||
if (!RANDOM_G(fallback_seed_initialized)) {
|
||||
if (!state->initialized) {
|
||||
/* Current time. */
|
||||
gettimeofday(&tv, NULL);
|
||||
fallback_seed_add(&c, &tv, sizeof(tv));
|
||||
|
@ -644,7 +644,7 @@ PHPAPI uint64_t php_random_generate_fallback_seed(void)
|
|||
fallback_seed_add(&c, &tid, sizeof(tid));
|
||||
#endif
|
||||
/* Pointer values to benefit from ASLR. */
|
||||
pointer = &RANDOM_G(fallback_seed_initialized);
|
||||
pointer = &state;
|
||||
fallback_seed_add(&c, &pointer, sizeof(pointer));
|
||||
pointer = &c;
|
||||
fallback_seed_add(&c, &pointer, sizeof(pointer));
|
||||
|
@ -668,24 +668,29 @@ PHPAPI uint64_t php_random_generate_fallback_seed(void)
|
|||
gettimeofday(&tv, NULL);
|
||||
fallback_seed_add(&c, &tv, sizeof(tv));
|
||||
/* Previous state. */
|
||||
fallback_seed_add(&c, RANDOM_G(fallback_seed), 20);
|
||||
fallback_seed_add(&c, state->seed, 20);
|
||||
}
|
||||
PHP_SHA1Final(RANDOM_G(fallback_seed), &c);
|
||||
RANDOM_G(fallback_seed_initialized) = true;
|
||||
PHP_SHA1Final(state->seed, &c);
|
||||
state->initialized = true;
|
||||
|
||||
uint64_t result = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(result); i++) {
|
||||
result = result | (((uint64_t)RANDOM_G(fallback_seed)[i]) << (i * 8));
|
||||
result = result | (((uint64_t)state->seed[i]) << (i * 8));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PHPAPI uint64_t php_random_generate_fallback_seed(void)
|
||||
{
|
||||
return php_random_generate_fallback_seed_ex(&RANDOM_G(fallback_seed_state));
|
||||
}
|
||||
|
||||
/* {{{ PHP_GINIT_FUNCTION */
|
||||
static PHP_GINIT_FUNCTION(random)
|
||||
{
|
||||
random_globals->fallback_seed_initialized = false;
|
||||
random_globals->fallback_seed_state.initialized = false;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
|
64
ext/random/zend_utils.c
Normal file
64
ext/random/zend_utils.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Arnaud Le Blanc <arnaud.lb@gmail.com> |
|
||||
| Tim Düsterhus <timwolla@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "php_random_zend_utils.h"
|
||||
|
||||
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_random_bytes_insecure_for_zend(
|
||||
zend_random_bytes_insecure_state *opaque_state, void *bytes, size_t size)
|
||||
{
|
||||
php_random_bytes_insecure_state_for_zend *state = (php_random_bytes_insecure_state_for_zend*) opaque_state;
|
||||
|
||||
if (UNEXPECTED(!state->initialized)) {
|
||||
uint64_t t[4];
|
||||
php_random_fallback_seed_state fallback_state;
|
||||
fallback_state.initialized = false;
|
||||
|
||||
do {
|
||||
/* Skip the CSPRNG if it has already failed */
|
||||
if (!fallback_state.initialized) {
|
||||
char errstr[128];
|
||||
if (php_random_bytes_ex(&t, sizeof(t), errstr, sizeof(errstr)) == FAILURE) {
|
||||
#if ZEND_DEBUG
|
||||
fprintf(stderr, "php_random_bytes_ex: Failed to generate a random seed: %s\n", errstr);
|
||||
#endif
|
||||
goto fallback;
|
||||
}
|
||||
} else {
|
||||
fallback:
|
||||
t[0] = php_random_generate_fallback_seed_ex(&fallback_state);
|
||||
t[1] = php_random_generate_fallback_seed_ex(&fallback_state);
|
||||
t[2] = php_random_generate_fallback_seed_ex(&fallback_state);
|
||||
t[3] = php_random_generate_fallback_seed_ex(&fallback_state);
|
||||
}
|
||||
} while (UNEXPECTED(t[0] == 0 && t[1] == 0 && t[2] == 0 && t[3] == 0));
|
||||
|
||||
php_random_xoshiro256starstar_seed256(&state->xoshiro256starstar_state, t[0], t[1], t[2], t[3]);
|
||||
state->initialized = true;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
php_random_result result = php_random_algo_xoshiro256starstar.generate(&state->xoshiro256starstar_state);
|
||||
ZEND_ASSERT(result.size == 8 && sizeof(result.result) == 8);
|
||||
size_t chunk_size = MIN(size, 8);
|
||||
bytes = zend_mempcpy(bytes, &result.result, chunk_size);
|
||||
size -= chunk_size;
|
||||
}
|
||||
}
|
|
@ -49,6 +49,8 @@
|
|||
#include "fopen_wrappers.h"
|
||||
#include "ext/standard/php_standard.h"
|
||||
#include "ext/date/php_date.h"
|
||||
#include "ext/random/php_random_csprng.h"
|
||||
#include "ext/random/php_random_zend_utils.h"
|
||||
#include "php_variables.h"
|
||||
#include "ext/standard/credits.h"
|
||||
#ifdef PHP_WIN32
|
||||
|
@ -2119,6 +2121,8 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi
|
|||
zuf.printf_to_smart_str_function = php_printf_to_smart_str;
|
||||
zuf.getenv_function = sapi_getenv;
|
||||
zuf.resolve_path_function = php_resolve_path_for_zend;
|
||||
zuf.random_bytes_function = php_random_bytes_ex;
|
||||
zuf.random_bytes_insecure_function = php_random_bytes_insecure_for_zend;
|
||||
zend_startup(&zuf);
|
||||
zend_reset_lc_ctype_locale();
|
||||
zend_update_current_locale();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue