rebase to 8.3.7
backport Argon2 password hashing in OpenSSL ext Fix CVE-2024-2756 CVE-2024-2757 CVE-2024-3096 Resolves: RHEL-32794 Resolves: RHEL-32749 Resolves: RHEL-32762 Resolves: RHEL-36582
This commit is contained in:
parent
e928cf5b22
commit
fb86031406
24
.gitignore
vendored
24
.gitignore
vendored
@ -1,27 +1,11 @@
|
||||
clog
|
||||
TODO
|
||||
*.md
|
||||
/php-8.0.*.tar.xz
|
||||
/php-8.0.*.tar.xz.asc
|
||||
/php-8.1.*.tar.xz
|
||||
/php-8.1.*.tar.xz.asc
|
||||
/php-8.2.*.tar.xz
|
||||
/php-8.2.*.tar.xz.asc
|
||||
/php-8.3.0RC3.tar.xz
|
||||
/php-8.3.0RC3.tar.xz.asc
|
||||
/php-8.3.0RC4.tar.xz
|
||||
/php-8.3.0RC4.tar.xz.asc
|
||||
/php-8.3.0RC5.tar.xz
|
||||
/php-8.3.0RC5.tar.xz.asc
|
||||
/php-8.3.0RC6.tar.xz
|
||||
/php-8.3.0RC6.tar.xz.asc
|
||||
/php-8.3.0.tar.xz
|
||||
/php-8.3.0.tar.xz.asc
|
||||
/php-8.3.1RC3.tar.xz
|
||||
/php-8.3.1RC3.tar.xz.asc
|
||||
/php-8.3.1.tar.xz
|
||||
/php-8.3.1.tar.xz.asc
|
||||
/php-8.3.2RC1.tar.xz
|
||||
/php-8.3.2RC1.tar.xz.asc
|
||||
/php-8.3.2.tar.xz
|
||||
/php-8.3.2.tar.xz.asc
|
||||
/php-8.3.3RC1.tar.xz
|
||||
/php-8.3.3RC1.tar.xz.asc
|
||||
/php-8.3.7.tar.xz
|
||||
/php-8.3.7.tar.xz.asc
|
||||
|
842
php-8.3.7-argon2.patch
Normal file
842
php-8.3.7-argon2.patch
Normal file
@ -0,0 +1,842 @@
|
||||
From c6c39b2b1cb1ff9916a8db606b19fc4282feacd2 Mon Sep 17 00:00:00 2001
|
||||
From: Remi Collet <remi@remirepo.net>
|
||||
Date: Wed, 17 Apr 2024 15:58:49 +0200
|
||||
Subject: [PATCH] Implement PASSWORD_ARGON2 from OpenSSL 3.2 Backported from
|
||||
8.4 to 8.3
|
||||
|
||||
---
|
||||
ext/openssl/config0.m4 | 2 +-
|
||||
ext/openssl/openssl.c | 24 +
|
||||
ext/openssl/openssl_pwhash.c | 412 ++++++++++++++++++
|
||||
ext/openssl/openssl_pwhash.stub.php | 38 ++
|
||||
ext/openssl/openssl_pwhash_arginfo.h | Bin 0 -> 2571 bytes
|
||||
ext/openssl/php_openssl.h | 31 +-
|
||||
ext/openssl/tests/openssl_password.phpt | 42 ++
|
||||
.../tests/openssl_password_compat.phpt | 52 +++
|
||||
.../tests/openssl_password_compat2.phpt | 52 +++
|
||||
9 files changed, 651 insertions(+), 2 deletions(-)
|
||||
create mode 100644 ext/openssl/openssl_pwhash.c
|
||||
create mode 100644 ext/openssl/openssl_pwhash.stub.php
|
||||
create mode 100644 ext/openssl/openssl_pwhash_arginfo.h
|
||||
create mode 100644 ext/openssl/tests/openssl_password.phpt
|
||||
create mode 100644 ext/openssl/tests/openssl_password_compat.phpt
|
||||
create mode 100644 ext/openssl/tests/openssl_password_compat2.phpt
|
||||
|
||||
diff --git a/ext/openssl/config0.m4 b/ext/openssl/config0.m4
|
||||
index ffd4e0751c..aae3812752 100644
|
||||
--- a/ext/openssl/config0.m4
|
||||
+++ b/ext/openssl/config0.m4
|
||||
@@ -18,7 +18,7 @@ PHP_ARG_WITH([system-ciphers],
|
||||
[no])
|
||||
|
||||
if test "$PHP_OPENSSL" != "no"; then
|
||||
- PHP_NEW_EXTENSION(openssl, openssl.c xp_ssl.c, $ext_shared)
|
||||
+ PHP_NEW_EXTENSION(openssl, openssl.c openssl_pwhash.c xp_ssl.c, $ext_shared)
|
||||
PHP_SUBST(OPENSSL_SHARED_LIBADD)
|
||||
|
||||
if test "$PHP_KERBEROS" != "no"; then
|
||||
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
|
||||
index 6f85e9852f..1f164a60b6 100644
|
||||
--- a/ext/openssl/openssl.c
|
||||
+++ b/ext/openssl/openssl.c
|
||||
@@ -263,9 +263,21 @@ static void php_openssl_pkey_free_obj(zend_object *object)
|
||||
zend_object_std_dtor(&key_object->std);
|
||||
}
|
||||
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+static const zend_module_dep openssl_deps[] = {
|
||||
+ ZEND_MOD_REQUIRED("standard")
|
||||
+ ZEND_MOD_END
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
/* {{{ openssl_module_entry */
|
||||
zend_module_entry openssl_module_entry = {
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ STANDARD_MODULE_HEADER_EX, NULL,
|
||||
+ openssl_deps,
|
||||
+#else
|
||||
STANDARD_MODULE_HEADER,
|
||||
+#endif
|
||||
"openssl",
|
||||
ext_functions,
|
||||
PHP_MINIT(openssl),
|
||||
@@ -1321,6 +1333,12 @@ PHP_MINIT_FUNCTION(openssl)
|
||||
|
||||
REGISTER_INI_ENTRIES();
|
||||
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ if (FAILURE == PHP_MINIT(openssl_pwhash)(INIT_FUNC_ARGS_PASSTHRU)) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -1395,6 +1413,12 @@ PHP_MSHUTDOWN_FUNCTION(openssl)
|
||||
php_stream_xport_unregister("tlsv1.3");
|
||||
#endif
|
||||
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ if (FAILURE == PHP_MSHUTDOWN(openssl_pwhash)(SHUTDOWN_FUNC_ARGS_PASSTHRU)) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
/* reinstate the default tcp handler */
|
||||
php_stream_xport_register("tcp", php_stream_generic_socket_factory);
|
||||
|
||||
diff --git a/ext/openssl/openssl_pwhash.c b/ext/openssl/openssl_pwhash.c
|
||||
new file mode 100644
|
||||
index 0000000000..56ab62ff83
|
||||
--- /dev/null
|
||||
+++ b/ext/openssl/openssl_pwhash.c
|
||||
@@ -0,0 +1,412 @@
|
||||
+/*
|
||||
+ +----------------------------------------------------------------------+
|
||||
+ | 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: Remi Collet <remi@php.net> |
|
||||
+ +----------------------------------------------------------------------+
|
||||
+*/
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+# include "config.h"
|
||||
+#endif
|
||||
+
|
||||
+#include "php.h"
|
||||
+#include "ext/standard/php_password.h"
|
||||
+#include "php_openssl.h"
|
||||
+
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+#include "Zend/zend_attributes.h"
|
||||
+#include "openssl_pwhash_arginfo.h"
|
||||
+#include <ext/standard/base64.h>
|
||||
+#include <openssl/params.h>
|
||||
+#include <openssl/core_names.h>
|
||||
+#include <openssl/kdf.h>
|
||||
+#include <openssl/thread.h>
|
||||
+#include <openssl/rand.h>
|
||||
+
|
||||
+#define PHP_OPENSSL_MEMLIMIT_MIN 8u
|
||||
+#define PHP_OPENSSL_MEMLIMIT_MAX UINT32_MAX
|
||||
+#define PHP_OPENSSL_ITERLIMIT_MIN 1u
|
||||
+#define PHP_OPENSSL_ITERLIMIT_MAX UINT32_MAX
|
||||
+#define PHP_OPENSSL_THREADS_MIN 1u
|
||||
+#define PHP_OPENSSL_THREADS_MAX UINT32_MAX
|
||||
+
|
||||
+#define PHP_OPENSSL_ARGON_VERSION 0x13
|
||||
+
|
||||
+#define PHP_OPENSSL_SALT_SIZE 16
|
||||
+#define PHP_OPENSSL_HASH_SIZE 32
|
||||
+#define PHP_OPENSSL_DIGEST_SIZE 128
|
||||
+
|
||||
+static inline zend_result get_options(zend_array *options, uint32_t *memlimit, uint32_t *iterlimit, uint32_t *threads)
|
||||
+{
|
||||
+ zval *opt;
|
||||
+
|
||||
+ *iterlimit = PHP_OPENSSL_PWHASH_ITERLIMIT;
|
||||
+ *memlimit = PHP_OPENSSL_PWHASH_MEMLIMIT;
|
||||
+ *threads = PHP_OPENSSL_PWHASH_THREADS;
|
||||
+
|
||||
+ if (!options) {
|
||||
+ return SUCCESS;
|
||||
+ }
|
||||
+ if ((opt = zend_hash_str_find(options, "memory_cost", strlen("memory_cost")))) {
|
||||
+ zend_long smemlimit = zval_get_long(opt);
|
||||
+
|
||||
+ if ((smemlimit < 0) || (smemlimit < PHP_OPENSSL_MEMLIMIT_MIN) || (smemlimit > (PHP_OPENSSL_MEMLIMIT_MAX))) {
|
||||
+ zend_value_error("Memory cost is outside of allowed memory range");
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ *memlimit = smemlimit;
|
||||
+ }
|
||||
+ if ((opt = zend_hash_str_find(options, "time_cost", strlen("time_cost")))) {
|
||||
+ zend_long siterlimit = zval_get_long(opt);
|
||||
+ if ((siterlimit < PHP_OPENSSL_ITERLIMIT_MIN) || (siterlimit > PHP_OPENSSL_ITERLIMIT_MAX)) {
|
||||
+ zend_value_error("Time cost is outside of allowed time range");
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ *iterlimit = siterlimit;
|
||||
+ }
|
||||
+ if ((opt = zend_hash_str_find(options, "threads", strlen("threads"))) && (zval_get_long(opt) != 1)) {
|
||||
+ zend_long sthreads = zval_get_long(opt);
|
||||
+ if ((sthreads < PHP_OPENSSL_THREADS_MIN) || (sthreads > PHP_OPENSSL_THREADS_MAX)) {
|
||||
+ zend_value_error("Invalid number of threads");
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ *threads = sthreads;
|
||||
+ }
|
||||
+ return SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static bool php_openssl_argon2_compute_hash(
|
||||
+ const char *algo,
|
||||
+ uint32_t version, uint32_t memlimit, uint32_t iterlimit, uint32_t threads,
|
||||
+ const char *pass, size_t pass_len,
|
||||
+ const unsigned char *salt, size_t salt_len,
|
||||
+ unsigned char *hash, size_t hash_len)
|
||||
+{
|
||||
+ OSSL_PARAM params[7], *p = params;
|
||||
+ EVP_KDF *kdf = NULL;
|
||||
+ EVP_KDF_CTX *kctx = NULL;
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ if (threads > 1) {
|
||||
+ if (OSSL_set_max_threads(NULL, threads) != 1) {
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ }
|
||||
+ p = params;
|
||||
+ *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_THREADS,
|
||||
+ &threads);
|
||||
+ *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ARGON2_LANES,
|
||||
+ &threads);
|
||||
+ *p++= OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ITER,
|
||||
+ &iterlimit);
|
||||
+ *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ARGON2_MEMCOST,
|
||||
+ &memlimit);
|
||||
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT,
|
||||
+ (void *)salt, salt_len);
|
||||
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD,
|
||||
+ (void *)pass, pass_len);
|
||||
+ *p++ = OSSL_PARAM_construct_end();
|
||||
+
|
||||
+ if ((kdf = EVP_KDF_fetch(NULL, algo, NULL)) == NULL) {
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if ((kctx = EVP_KDF_CTX_new(kdf)) == NULL) {
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (EVP_KDF_derive(kctx, hash, hash_len, params) != 1) {
|
||||
+ zend_value_error("Unexpected failure hashing password");
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ ret = true;
|
||||
+
|
||||
+fail:
|
||||
+ EVP_KDF_free(kdf);
|
||||
+ EVP_KDF_CTX_free(kctx);
|
||||
+
|
||||
+ if (threads > 1) {
|
||||
+ OSSL_set_max_threads(NULL, 0);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static zend_string *php_openssl_argon2_hash(const zend_string *password, zend_array *options, const char *algo)
|
||||
+{
|
||||
+ uint32_t iterlimit, memlimit, threads, version = PHP_OPENSSL_ARGON_VERSION;
|
||||
+ zend_string *digest = NULL, *salt64 = NULL, *hash64 = NULL;
|
||||
+ unsigned char hash[PHP_OPENSSL_HASH_SIZE+1], salt[PHP_OPENSSL_SALT_SIZE+1];
|
||||
+
|
||||
+ if ((ZSTR_LEN(password) >= UINT32_MAX)) {
|
||||
+ zend_value_error("Password is too long");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ if (get_options(options, &memlimit, &iterlimit, &threads) == FAILURE) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ if (RAND_bytes(salt, PHP_OPENSSL_SALT_SIZE) <= 0) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (!php_openssl_argon2_compute_hash(algo, version, memlimit, iterlimit, threads,
|
||||
+ ZSTR_VAL(password), ZSTR_LEN(password), salt, PHP_OPENSSL_SALT_SIZE, hash, PHP_OPENSSL_HASH_SIZE)) {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ hash64 = php_base64_encode(hash, PHP_OPENSSL_HASH_SIZE);
|
||||
+ /* No padding utsing 32 *4 / 3 = 42.6 (43 + 1 padding char) */
|
||||
+ ZEND_ASSERT(ZSTR_LEN(hash64)==44 && ZSTR_VAL(hash64)[43]=='=');
|
||||
+ ZSTR_VAL(hash64)[43] = 0;
|
||||
+ ZSTR_LEN(hash64) = 43;
|
||||
+
|
||||
+ salt64 = php_base64_encode(salt, PHP_OPENSSL_SALT_SIZE);
|
||||
+ /* No padding using 16 *4 / 3 = 21.3 (22 + 2 padding char) */
|
||||
+ ZEND_ASSERT(ZSTR_LEN(salt64)==24 && ZSTR_VAL(salt64)[22]=='=' && ZSTR_VAL(salt64)[23]=='=');
|
||||
+ ZSTR_VAL(salt64)[22] = 0;
|
||||
+ ZSTR_LEN(salt64) = 22;
|
||||
+
|
||||
+ digest = zend_string_alloc(PHP_OPENSSL_DIGEST_SIZE, 0);
|
||||
+ ZSTR_LEN(digest) = snprintf(ZSTR_VAL(digest), ZSTR_LEN(digest), "$%s$v=%d$m=%u,t=%u,p=%u$%s$%s",
|
||||
+ algo, version, memlimit, iterlimit, threads, ZSTR_VAL(salt64), ZSTR_VAL(hash64));
|
||||
+
|
||||
+ zend_string_release(salt64);
|
||||
+ zend_string_release(hash64);
|
||||
+
|
||||
+ return digest;
|
||||
+}
|
||||
+
|
||||
+static int php_openssl_argon2_extract(
|
||||
+ const zend_string *digest, uint32_t *version, uint32_t *memlimit, uint32_t *iterlimit,
|
||||
+ uint32_t *threads, zend_string **salt, zend_string **hash)
|
||||
+{
|
||||
+ const char *p;
|
||||
+ char *hash64, *salt64;
|
||||
+
|
||||
+ if (!digest || (ZSTR_LEN(digest) < sizeof("$argon2id$"))) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ p = ZSTR_VAL(digest);
|
||||
+ if (!memcmp(p, "$argon2i$", strlen("$argon2i$"))) {
|
||||
+ p += strlen("$argon2i$");
|
||||
+ } else if (!memcmp(p, "$argon2id$", strlen("$argon2id$"))) {
|
||||
+ p += strlen("$argon2id$");
|
||||
+ } else {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ if (sscanf(p, "v=%" PRIu32 "$m=%" PRIu32 ",t=%" PRIu32 ",p=%" PRIu32,
|
||||
+ version, memlimit, iterlimit, threads) != 4) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ if (salt && hash) {
|
||||
+ /* start of param */
|
||||
+ p = strchr(p, '$');
|
||||
+ if (!p) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ /* start of salt */
|
||||
+ p = strchr(p+1, '$');
|
||||
+ if (!p) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ salt64 = estrdup(p+1);
|
||||
+ /* start of hash */
|
||||
+ hash64 = strchr(salt64, '$');
|
||||
+ if (!hash64) {
|
||||
+ efree(salt64);
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ *hash64++ = 0;
|
||||
+ *salt = php_base64_decode((unsigned char *)salt64, strlen(salt64));
|
||||
+ *hash = php_base64_decode((unsigned char *)hash64, strlen(hash64));
|
||||
+ efree(salt64);
|
||||
+ }
|
||||
+ return SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static bool php_openssl_argon2_verify(const zend_string *password, const zend_string *digest, const char *algo)
|
||||
+{
|
||||
+ uint32_t version, iterlimit, memlimit, threads;
|
||||
+ zend_string *salt, *hash, *new;
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ if ((ZSTR_LEN(password) >= UINT32_MAX) || (ZSTR_LEN(digest) >= UINT32_MAX)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (FAILURE == php_openssl_argon2_extract(digest, &version, &memlimit, &iterlimit, &threads, &salt, &hash)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ new = zend_string_alloc(ZSTR_LEN(hash), 0);
|
||||
+ if (php_openssl_argon2_compute_hash(algo, version, memlimit, iterlimit, threads,
|
||||
+ ZSTR_VAL(password), ZSTR_LEN(password), (unsigned char *)ZSTR_VAL(salt),
|
||||
+ ZSTR_LEN(salt), (unsigned char *)ZSTR_VAL(new), ZSTR_LEN(new))) {
|
||||
+ ret = (php_safe_bcmp(hash, new) == 0);
|
||||
+ }
|
||||
+
|
||||
+ zend_string_release(new);
|
||||
+ zend_string_release(salt);
|
||||
+ zend_string_release(hash);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static bool php_openssl_argon2i_verify(const zend_string *password, const zend_string *digest)
|
||||
+{
|
||||
+ return php_openssl_argon2_verify(password, digest, "argon2i");
|
||||
+}
|
||||
+
|
||||
+static bool php_openssl_argon2id_verify(const zend_string *password, const zend_string *digest)
|
||||
+{
|
||||
+ return php_openssl_argon2_verify(password, digest, "argon2id");
|
||||
+}
|
||||
+
|
||||
+static bool php_openssl_argon2_needs_rehash(const zend_string *hash, zend_array *options)
|
||||
+{
|
||||
+ uint32_t version, iterlimit, memlimit, threads;
|
||||
+ uint32_t new_version = PHP_OPENSSL_ARGON_VERSION, new_iterlimit, new_memlimit, new_threads;
|
||||
+
|
||||
+ if (FAILURE == get_options(options, &new_memlimit, &new_iterlimit, &new_threads)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ if (FAILURE == php_openssl_argon2_extract(hash, &version, &memlimit, &iterlimit, &threads, NULL, NULL)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ // Algo already checked in pasword_needs_rehash implementation
|
||||
+ return (version != new_version) ||
|
||||
+ (iterlimit != new_iterlimit) ||
|
||||
+ (memlimit != new_memlimit) ||
|
||||
+ (threads != new_threads);
|
||||
+}
|
||||
+
|
||||
+static int php_openssl_argon2_get_info(zval *return_value, const zend_string *hash)
|
||||
+{
|
||||
+ uint32_t v, threads;
|
||||
+ uint32_t memory_cost;
|
||||
+ uint32_t time_cost;
|
||||
+
|
||||
+ if (FAILURE == php_openssl_argon2_extract(hash, &v, &memory_cost, &time_cost, &threads, NULL, NULL)) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ add_assoc_long(return_value, "memory_cost", memory_cost);
|
||||
+ add_assoc_long(return_value, "time_cost", time_cost);
|
||||
+ add_assoc_long(return_value, "threads", threads);
|
||||
+
|
||||
+ return SUCCESS;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static zend_string *php_openssl_argon2i_hash(const zend_string *password, zend_array *options)
|
||||
+{
|
||||
+ return php_openssl_argon2_hash(password, options, "argon2i");
|
||||
+}
|
||||
+
|
||||
+static const php_password_algo openssl_algo_argon2i = {
|
||||
+ "argon2i",
|
||||
+ php_openssl_argon2i_hash,
|
||||
+ php_openssl_argon2i_verify,
|
||||
+ php_openssl_argon2_needs_rehash,
|
||||
+ php_openssl_argon2_get_info,
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
+static zend_string *php_openssl_argon2id_hash(const zend_string *password, zend_array *options)
|
||||
+{
|
||||
+ return php_openssl_argon2_hash(password, options, "argon2id");
|
||||
+}
|
||||
+
|
||||
+static const php_password_algo openssl_algo_argon2id = {
|
||||
+ "argon2id",
|
||||
+ php_openssl_argon2id_hash,
|
||||
+ php_openssl_argon2id_verify,
|
||||
+ php_openssl_argon2_needs_rehash,
|
||||
+ php_openssl_argon2_get_info,
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
+PHP_FUNCTION(openssl_password_hash)
|
||||
+{
|
||||
+ zend_string *password, *algo, *digest;
|
||||
+ zend_array *options = NULL;
|
||||
+
|
||||
+ ZEND_PARSE_PARAMETERS_START(2, 3)
|
||||
+ Z_PARAM_STR(algo)
|
||||
+ Z_PARAM_STR(password)
|
||||
+ Z_PARAM_OPTIONAL
|
||||
+ Z_PARAM_ARRAY_HT(options)
|
||||
+ ZEND_PARSE_PARAMETERS_END();
|
||||
+
|
||||
+ if (strcmp(ZSTR_VAL(algo), "argon2i") && strcmp(ZSTR_VAL(algo), "argon2id")) {
|
||||
+ zend_argument_value_error(1, "must be a valid password openssl hashing algorithm");
|
||||
+ RETURN_THROWS();
|
||||
+ }
|
||||
+
|
||||
+ digest = php_openssl_argon2_hash(password, options, ZSTR_VAL(algo));
|
||||
+ if (!digest) {
|
||||
+ if (!EG(exception)) {
|
||||
+ zend_throw_error(NULL, "Password hashing failed for unknown reason");
|
||||
+ }
|
||||
+ RETURN_THROWS();
|
||||
+ }
|
||||
+
|
||||
+ RETURN_NEW_STR(digest);
|
||||
+}
|
||||
+
|
||||
+PHP_FUNCTION(openssl_password_verify)
|
||||
+{
|
||||
+ zend_string *password, *algo, *digest;
|
||||
+
|
||||
+ ZEND_PARSE_PARAMETERS_START(3, 3)
|
||||
+ Z_PARAM_STR(algo)
|
||||
+ Z_PARAM_STR(password)
|
||||
+ Z_PARAM_STR(digest)
|
||||
+ ZEND_PARSE_PARAMETERS_END();
|
||||
+
|
||||
+ if (strcmp(ZSTR_VAL(algo), "argon2i") && strcmp(ZSTR_VAL(algo), "argon2id")) {
|
||||
+ zend_argument_value_error(1, "must be a valid password openssl hashing algorithm");
|
||||
+ RETURN_THROWS();
|
||||
+ }
|
||||
+
|
||||
+ RETURN_BOOL(php_openssl_argon2_verify(password, digest, ZSTR_VAL(algo)));
|
||||
+}
|
||||
+
|
||||
+PHP_MINIT_FUNCTION(openssl_pwhash)
|
||||
+{
|
||||
+ zend_string *argon2i = ZSTR_INIT_LITERAL("argon2i", 1);
|
||||
+
|
||||
+ zend_register_functions(NULL, ext_functions, NULL, type);
|
||||
+
|
||||
+ if (php_password_algo_find(argon2i)) {
|
||||
+ /* Nothing to do. Core or sodium has registered these algorithms for us. */
|
||||
+ zend_string_release(argon2i);
|
||||
+ return SUCCESS;
|
||||
+ }
|
||||
+ zend_string_release(argon2i);
|
||||
+
|
||||
+ register_openssl_pwhash_symbols(module_number);
|
||||
+
|
||||
+ if (FAILURE == php_password_algo_register("argon2i", &openssl_algo_argon2i)) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+ if (FAILURE == php_password_algo_register("argon2id", &openssl_algo_argon2id)) {
|
||||
+ return FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ return SUCCESS;
|
||||
+}
|
||||
+
|
||||
+PHP_MSHUTDOWN_FUNCTION(openssl_pwhash)
|
||||
+{
|
||||
+ zend_unregister_functions(ext_functions, -1, NULL);
|
||||
+
|
||||
+ return SUCCESS;
|
||||
+}
|
||||
+#endif /* PHP_OPENSSL_API_VERSION >= 0x30200 */
|
||||
diff --git a/ext/openssl/openssl_pwhash.stub.php b/ext/openssl/openssl_pwhash.stub.php
|
||||
new file mode 100644
|
||||
index 0000000000..85c2f04d55
|
||||
--- /dev/null
|
||||
+++ b/ext/openssl/openssl_pwhash.stub.php
|
||||
@@ -0,0 +1,38 @@
|
||||
+<?php
|
||||
+
|
||||
+/** @generate-class-entries */
|
||||
+
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+/**
|
||||
+ * @var string
|
||||
+ */
|
||||
+const PASSWORD_ARGON2I = "argon2i";
|
||||
+/**
|
||||
+ * @var string
|
||||
+ */
|
||||
+const PASSWORD_ARGON2ID = "argon2id";
|
||||
+/**
|
||||
+ * @var int
|
||||
+ * @cvalue PHP_OPENSSL_PWHASH_MEMLIMIT
|
||||
+ */
|
||||
+const PASSWORD_ARGON2_DEFAULT_MEMORY_COST = UNKNOWN;
|
||||
+/**
|
||||
+ * @var int
|
||||
+ * @cvalue PHP_OPENSSL_PWHASH_ITERLIMIT
|
||||
+ */
|
||||
+const PASSWORD_ARGON2_DEFAULT_TIME_COST = UNKNOWN;
|
||||
+/**
|
||||
+ * @var int
|
||||
+ * @cvalue PHP_OPENSSL_PWHASH_THREADS
|
||||
+ */
|
||||
+const PASSWORD_ARGON2_DEFAULT_THREADS = UNKNOWN;
|
||||
+/**
|
||||
+ * @var string
|
||||
+ */
|
||||
+const PASSWORD_ARGON2_PROVIDER = "openssl";
|
||||
+
|
||||
+function openssl_password_hash(string $algo, #[\SensitiveParameter] string $password, array $options = []): string {}
|
||||
+function openssl_password_verify(string $algo, #[\SensitiveParameter] string $password, string $hash): bool {}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
diff --git a/ext/openssl/openssl_pwhash_arginfo.h b/ext/openssl/openssl_pwhash_arginfo.h
|
||||
new file mode 100644
|
||||
index 0000000000..f60a1f5b08
|
||||
--- /dev/null
|
||||
+++ b/ext/openssl/openssl_pwhash_arginfo.h
|
||||
@@ -0,0 +1,68 @@
|
||||
+/* This is a generated file, edit the .stub.php file instead.
|
||||
+ * Stub hash: a01216f790c4c42499bd85448aacb3a6d58acc94 */
|
||||
+
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_password_hash, 0, 2, IS_STRING, 0)
|
||||
+ ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0)
|
||||
+ ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 0)
|
||||
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
|
||||
+ZEND_END_ARG_INFO()
|
||||
+#endif
|
||||
+
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_password_verify, 0, 3, _IS_BOOL, 0)
|
||||
+ ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0)
|
||||
+ ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 0)
|
||||
+ ZEND_ARG_TYPE_INFO(0, hash, IS_STRING, 0)
|
||||
+ZEND_END_ARG_INFO()
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ZEND_FUNCTION(openssl_password_hash);
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ZEND_FUNCTION(openssl_password_verify);
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+static const zend_function_entry ext_functions[] = {
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ ZEND_FE(openssl_password_hash, arginfo_openssl_password_hash)
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ ZEND_FE(openssl_password_verify, arginfo_openssl_password_verify)
|
||||
+#endif
|
||||
+ ZEND_FE_END
|
||||
+};
|
||||
+
|
||||
+static void register_openssl_pwhash_symbols(int module_number)
|
||||
+{
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ REGISTER_STRING_CONSTANT("PASSWORD_ARGON2I", "argon2i", CONST_PERSISTENT);
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ REGISTER_STRING_CONSTANT("PASSWORD_ARGON2ID", "argon2id", CONST_PERSISTENT);
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_MEMORY_COST", PHP_OPENSSL_PWHASH_MEMLIMIT, CONST_PERSISTENT);
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_TIME_COST", PHP_OPENSSL_PWHASH_ITERLIMIT, CONST_PERSISTENT);
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ REGISTER_LONG_CONSTANT("PASSWORD_ARGON2_DEFAULT_THREADS", PHP_OPENSSL_PWHASH_THREADS, CONST_PERSISTENT);
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+ REGISTER_STRING_CONSTANT("PASSWORD_ARGON2_PROVIDER", "openssl", CONST_PERSISTENT);
|
||||
+#endif
|
||||
+
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+
|
||||
+ zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "openssl_password_hash", sizeof("openssl_password_hash") - 1), 1, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
|
||||
+#endif
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+
|
||||
+ zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "openssl_password_verify", sizeof("openssl_password_verify") - 1), 1, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
|
||||
+#endif
|
||||
+}
|
||||
diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h
|
||||
index 304854b4bf..9532cfe6f9 100644
|
||||
--- a/ext/openssl/php_openssl.h
|
||||
+++ b/ext/openssl/php_openssl.h
|
||||
@@ -39,8 +39,10 @@ extern zend_module_entry openssl_module_entry;
|
||||
#define PHP_OPENSSL_API_VERSION 0x10002
|
||||
#elif OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#define PHP_OPENSSL_API_VERSION 0x10100
|
||||
-#else
|
||||
+#elif OPENSSL_VERSION_NUMBER < 0x30200000L
|
||||
#define PHP_OPENSSL_API_VERSION 0x30000
|
||||
+#else
|
||||
+#define PHP_OPENSSL_API_VERSION 0x30200
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -158,6 +160,33 @@ static inline php_openssl_certificate_object *php_openssl_certificate_from_obj(z
|
||||
|
||||
#define Z_OPENSSL_CERTIFICATE_P(zv) php_openssl_certificate_from_obj(Z_OBJ_P(zv))
|
||||
|
||||
+#if PHP_OPENSSL_API_VERSION >= 0x30200
|
||||
+/**
|
||||
+ * MEMLIMIT is normalized to KB even though sodium uses Bytes in order to
|
||||
+ * present a consistent user-facing API.
|
||||
+ *
|
||||
+ * When updating these values, synchronize ext/standard/php_password.h values.
|
||||
+ */
|
||||
+#if defined(PHP_PASSWORD_ARGON2_MEMORY_COST)
|
||||
+#define PHP_OPENSSL_PWHASH_MEMLIMIT PHP_PASSWORD_ARGON2_MEMORY_COST
|
||||
+#else
|
||||
+#define PHP_OPENSSL_PWHASH_MEMLIMIT (64 << 10)
|
||||
+#endif
|
||||
+#if defined(PHP_PASSWORD_ARGON2_TIME_COST)
|
||||
+#define PHP_OPENSSL_PWHASH_ITERLIMIT PHP_PASSWORD_ARGON2_TIME_COST
|
||||
+#else
|
||||
+#define PHP_OPENSSL_PWHASH_ITERLIMIT 4
|
||||
+#endif
|
||||
+#if defined(PHP_PASSWORD_ARGON2_THREADS)
|
||||
+#define PHP_OPENSSL_PWHASH_THREADS PHP_PASSWORD_ARGON2_THREADS
|
||||
+#else
|
||||
+#define PHP_OPENSSL_PWHASH_THREADS 1
|
||||
+#endif
|
||||
+
|
||||
+PHP_MINIT_FUNCTION(openssl_pwhash);
|
||||
+PHP_MSHUTDOWN_FUNCTION(openssl_pwhash);
|
||||
+#endif
|
||||
+
|
||||
PHP_MINIT_FUNCTION(openssl);
|
||||
PHP_MSHUTDOWN_FUNCTION(openssl);
|
||||
PHP_MINFO_FUNCTION(openssl);
|
||||
diff --git a/ext/openssl/tests/openssl_password.phpt b/ext/openssl/tests/openssl_password.phpt
|
||||
new file mode 100644
|
||||
index 0000000000..7881803038
|
||||
--- /dev/null
|
||||
+++ b/ext/openssl/tests/openssl_password.phpt
|
||||
@@ -0,0 +1,42 @@
|
||||
+--TEST--
|
||||
+Basic features of password_hash
|
||||
+--EXTENSIONS--
|
||||
+openssl
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (!function_exists('openssl_password_hash')) {
|
||||
+ echo "skip - No openssl_password_hash";
|
||||
+}
|
||||
+?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+echo 'Argon2 provider: ';
|
||||
+var_dump(PASSWORD_ARGON2_PROVIDER);
|
||||
+
|
||||
+foreach([1, 2] as $mem) {
|
||||
+ foreach([1, 2] as $time) {
|
||||
+ $opts = [
|
||||
+ 'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST / $mem,
|
||||
+ 'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST / $time,
|
||||
+ 'threads' => PASSWORD_ARGON2_DEFAULT_THREADS,
|
||||
+ ];
|
||||
+ foreach(['argon2i', 'argon2id'] as $algo) {
|
||||
+ $pass = "secret$mem$time$algo";
|
||||
+ $hash = openssl_password_hash($algo, $pass, $opts);
|
||||
+ var_dump(openssl_password_verify($algo, $pass, $hash));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Argon2 provider: string(%d) "%s"
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+
|
||||
diff --git a/ext/openssl/tests/openssl_password_compat.phpt b/ext/openssl/tests/openssl_password_compat.phpt
|
||||
new file mode 100644
|
||||
index 0000000000..0de683616a
|
||||
--- /dev/null
|
||||
+++ b/ext/openssl/tests/openssl_password_compat.phpt
|
||||
@@ -0,0 +1,52 @@
|
||||
+--TEST--
|
||||
+Compatibility of password_hash (libsodium / openssl)
|
||||
+--EXTENSIONS--
|
||||
+openssl
|
||||
+sodium
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (!function_exists('sodium_crypto_pwhash_str_verify')) {
|
||||
+ echo "skip - No crypto_pwhash_str_verify";
|
||||
+}
|
||||
+
|
||||
+if (!function_exists('openssl_password_hash')) {
|
||||
+ echo "skip - No crypto_pwhash_str_verify";
|
||||
+}
|
||||
+?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+echo 'Argon2 provider: ';
|
||||
+var_dump(PASSWORD_ARGON2_PROVIDER);
|
||||
+
|
||||
+foreach([1, 2] as $mem) {
|
||||
+ foreach([1, 2] as $time) {
|
||||
+ $opts = [
|
||||
+ 'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST / $mem,
|
||||
+ 'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST / $time,
|
||||
+ 'threads' => PASSWORD_ARGON2_DEFAULT_THREADS,
|
||||
+ ];
|
||||
+ $algo = 'argon2id';
|
||||
+ $pass = "secret$mem$time$algo";
|
||||
+
|
||||
+ /* hash with libsodium / verify with openssl */
|
||||
+ $hash = sodium_crypto_pwhash_str($pass, PASSWORD_ARGON2_DEFAULT_TIME_COST / $time, PASSWORD_ARGON2_DEFAULT_MEMORY_COST / $mem);
|
||||
+ var_dump(openssl_password_verify($algo, $pass, $hash));
|
||||
+
|
||||
+ /* hash with openssl / verify with libsodium */
|
||||
+ $hash = openssl_password_hash($algo, $pass, $opts);
|
||||
+ var_dump(sodium_crypto_pwhash_str_verify($hash, $pass));
|
||||
+ }
|
||||
+}
|
||||
+?>
|
||||
+--EXPECTF--
|
||||
+Argon2 provider: string(%d) "%s"
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+
|
||||
diff --git a/ext/openssl/tests/openssl_password_compat2.phpt b/ext/openssl/tests/openssl_password_compat2.phpt
|
||||
new file mode 100644
|
||||
index 0000000000..42cf8682fd
|
||||
--- /dev/null
|
||||
+++ b/ext/openssl/tests/openssl_password_compat2.phpt
|
||||
@@ -0,0 +1,52 @@
|
||||
+--TEST--
|
||||
+Compatibility of password_hash (libargon2 / openssl)
|
||||
+--EXTENSIONS--
|
||||
+openssl
|
||||
+sodium
|
||||
+--SKIPIF--
|
||||
+<?php
|
||||
+if (PASSWORD_ARGON2_PROVIDER != "standard") {
|
||||
+ echo "skip - libargon2 not available";
|
||||
+}
|
||||
+
|
||||
+if (!function_exists('openssl_password_hash')) {
|
||||
+ echo "skip - No crypto_pwhash_str_verify";
|
||||
+}
|
||||
+?>
|
||||
+--FILE--
|
||||
+<?php
|
||||
+
|
||||
+echo 'Argon2 provider: ';
|
||||
+var_dump(PASSWORD_ARGON2_PROVIDER);
|
||||
+
|
||||
+foreach([1, 2] as $mem) {
|
||||
+ foreach([1, 2] as $time) {
|
||||
+ $opts = [
|
||||
+ 'memory_cost' => PASSWORD_ARGON2_DEFAULT_MEMORY_COST / $mem,
|
||||
+ 'time_cost' => PASSWORD_ARGON2_DEFAULT_TIME_COST / $time,
|
||||
+ 'threads' => PASSWORD_ARGON2_DEFAULT_THREADS,
|
||||
+ ];
|
||||
+ $algo = 'argon2id';
|
||||
+ $pass = "secret$mem$time$algo";
|
||||
+
|
||||
+ /* hash with libargon2 / verify with openssl */
|
||||
+ $hash = password_hash($pass, PASSWORD_ARGON2ID, $opts);
|
||||
+ var_dump(openssl_password_verify($algo, $pass, $hash));
|
||||
+
|
||||
+ /* hash with openssl / verify with libargon2 */
|
||||
+ $hash = openssl_password_hash($algo, $pass, $opts);
|
||||
+ var_dump(password_verify($pass, $hash));
|
||||
+ }
|
||||
+}
|
||||
+?>
|
||||
+--EXPECT--
|
||||
+Argon2 provider: string(8) "standard"
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+bool(true)
|
||||
+
|
||||
--
|
||||
2.45.0
|
||||
|
10
php.spec
10
php.spec
@ -64,8 +64,7 @@
|
||||
%bcond_with imap
|
||||
%bcond_without lmdb
|
||||
|
||||
%global upver 8.3.3
|
||||
%global rcver RC1
|
||||
%global upver 8.3.7
|
||||
|
||||
Summary: PHP scripting language for creating dynamic web sites
|
||||
Name: php
|
||||
@ -123,6 +122,8 @@ Patch47: php-8.1.0-phpinfo.patch
|
||||
# Always warn about missing curve_name
|
||||
# Both Fedora and RHEL do not support arbitrary EC parameters
|
||||
Patch48: php-8.3.0-openssl-ec-param.patch
|
||||
# Backport Argon2 password hashing in OpenSSL ext
|
||||
Patch49: php-8.3.7-argon2.patch
|
||||
|
||||
# Upstream fixes (100+)
|
||||
|
||||
@ -725,6 +726,7 @@ in pure PHP.
|
||||
%patch -P45 -p1 -b .ldap_r
|
||||
%patch -P47 -p1 -b .phpinfo
|
||||
%patch -P48 -p1 -b .ec-param
|
||||
%patch -P49 -p1 -b .argon2
|
||||
|
||||
# upstream patches
|
||||
|
||||
@ -1552,6 +1554,10 @@ systemctl try-restart php-fpm.service >/dev/null 2>&1 || :
|
||||
|
||||
|
||||
%changelog
|
||||
* Thu May 16 2024 Remi Collet <rcollet@redhat.com> - 8.3.7-1
|
||||
- rebase to 8.3.7
|
||||
- backport Argon2 password hashing in OpenSSL ext
|
||||
|
||||
* Wed Jan 31 2024 Remi Collet <remi@remirepo.net> - 8.3.2~RC1-1
|
||||
- update to 8.3.3RC1
|
||||
- drop GCC 14 patch merged upstream
|
||||
|
4
sources
4
sources
@ -1,2 +1,2 @@
|
||||
SHA512 (php-8.3.3RC1.tar.xz) = be802a7e9eb328add2e8b2a6d3fab3f9012469d43b3a5d6feacb9feed02ce446b617bb3fc7807697cd54f2935cbe4048a0356cc19f0f5b8e43b54877ab0719c9
|
||||
SHA512 (php-8.3.3RC1.tar.xz.asc) = 6a91cc39aeeea7cd6e8c93d152b05fc0afe3f25cac16443fcab5e193a650df51e8d6af7dc519f7b7aecbbd49b323fb073de77b6ff176acce64acc85438a801ff
|
||||
SHA512 (php-8.3.7.tar.xz) = ff2c16a5cc08b1a59a61eee9df75c4c9a6dda7054d48198b75d104c194e934109fed3665005ba798eeca3d7294d7dc81df3a14e63a527baf9f196e229068d9a3
|
||||
SHA512 (php-8.3.7.tar.xz.asc) = 2fce3c0302dd93c6a841af53fc6dc498b58ce38250fa047b5fb77e9e98b138f00441c759018589c646366f0656303bea6738db30febed9f689f01847551c5769
|
||||
|
Loading…
Reference in New Issue
Block a user