From a9509bedb5071db22e02371ae2e2eb143640dfc5 Mon Sep 17 00:00:00 2001 From: Rashed Hossain Date: Thu, 27 Aug 2026 13:58:58 +0600 Subject: [PATCH] Upgrade/Install: Update sodium_compat to v1.24.1. This release fixes Ed25519 main subgroup validation and ensures public key validation correctly rejects points not on the main prime order subgroup. References: * [https://github.com/paragonie/sodium_compat/compare/v1.24.0...v1.24.1 Full list of changes in sodium_compat 1.24.1] * [https://github.com/paragonie/sodium_compat/pull/207 Upstream PR for v1.x branch] Follow-up to [55699], [58752], [58753], [60787], [60905], [61419]. Props paragoninitiativeenterprises, wprashed. Fixes #65903. --- .../sodium_compat/src/Core/Curve25519.php | 1 + .../sodium_compat/src/Core/Ed25519.php | 2 +- .../sodium_compat/src/Core32/Curve25519.php | 1 + .../sodium_compat/src/Core32/Ed25519.php | 24 ++++++++++++++++--- src/wp-includes/sodium_compat/src/File.php | 6 +++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/sodium_compat/src/Core/Curve25519.php b/src/wp-includes/sodium_compat/src/Core/Curve25519.php index 284871114b0ba..7dab1cd0bbd7a 100644 --- a/src/wp-includes/sodium_compat/src/Core/Curve25519.php +++ b/src/wp-includes/sodium_compat/src/Core/Curve25519.php @@ -2899,6 +2899,7 @@ public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A) # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]); } + $r = self::ge_p1p1_to_p3($t); } # ge_p1p1_to_p3(r, &t); diff --git a/src/wp-includes/sodium_compat/src/Core/Ed25519.php b/src/wp-includes/sodium_compat/src/Core/Ed25519.php index bf6b5cfbd77f4..5cae0f180c4a7 100644 --- a/src/wp-includes/sodium_compat/src/Core/Ed25519.php +++ b/src/wp-includes/sodium_compat/src/Core/Ed25519.php @@ -119,7 +119,7 @@ public static function is_on_main_subgroup(ParagonIE_Sodium_Core_Curve25519_Ge_P { $p1 = self::ge_mul_l($A); $t = self::fe_sub($p1->Y, $p1->Z); - return self::fe_isnonzero($p1->X) && self::fe_isnonzero($t); + return !self::fe_isnonzero($p1->X) && !self::fe_isnonzero($t); } /** diff --git a/src/wp-includes/sodium_compat/src/Core32/Curve25519.php b/src/wp-includes/sodium_compat/src/Core32/Curve25519.php index aafffcd132bef..5a5f0babd6dc1 100644 --- a/src/wp-includes/sodium_compat/src/Core32/Curve25519.php +++ b/src/wp-includes/sodium_compat/src/Core32/Curve25519.php @@ -3154,6 +3154,7 @@ public static function ge_mul_l(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A) # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]); } + $r = self::ge_p1p1_to_p3($t); } # ge_p1p1_to_p3(r, &t); return self::ge_p1p1_to_p3($t); diff --git a/src/wp-includes/sodium_compat/src/Core32/Ed25519.php b/src/wp-includes/sodium_compat/src/Core32/Ed25519.php index 1b86b6774282b..8a0ea8e3e25a7 100644 --- a/src/wp-includes/sodium_compat/src/Core32/Ed25519.php +++ b/src/wp-includes/sodium_compat/src/Core32/Ed25519.php @@ -106,6 +106,22 @@ public static function publickey_from_secretkey($sk) return self::sk_to_pk($sk); } + /** + * Returns TRUE if $A represents a point on the order of the Edwards25519 prime order subgroup. + * Returns FALSE if $A is on a different subgroup. + * + * @param ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A + * @return bool + * + * @throws SodiumException + */ + public static function is_on_main_subgroup(ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A) + { + $p1 = self::ge_mul_l($A); + $t = self::fe_sub($p1->Y, $p1->Z); + return !self::fe_isnonzero($p1->X) && !self::fe_isnonzero($t); + } + /** * @param string $pk * @return string @@ -118,9 +134,8 @@ public static function pk_to_curve25519($pk) throw new SodiumException('Public key is on a small order'); } $A = self::ge_frombytes_negate_vartime($pk); - $p1 = self::ge_mul_l($A); - if (!self::fe_isnonzero($p1->X)) { - throw new SodiumException('Unexpected zero result'); + if (!self::is_on_main_subgroup($A)) { + throw new SodiumException('Public key is not on a member of the main subgroup'); } # fe_1(one_minus_y); @@ -307,6 +322,9 @@ public static function verify_detached($sig, $message, $pk) /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */ $A = self::ge_frombytes_negate_vartime($pk); + if (!self::is_on_main_subgroup($A)) { + throw new SodiumException('Public key is not on a member of the main subgroup'); + } /** @var string $hDigest */ $hDigest = hash( diff --git a/src/wp-includes/sodium_compat/src/File.php b/src/wp-includes/sodium_compat/src/File.php index c132a92e25fff..658dcd973612a 100644 --- a/src/wp-includes/sodium_compat/src/File.php +++ b/src/wp-includes/sodium_compat/src/File.php @@ -1329,8 +1329,14 @@ public static function verify_core32($sig, $filePath, $publicKey) // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. ParagonIE_Sodium_Compat::$fastMult = true; + if (ParagonIE_Sodium_Core32_Ed25519::small_order($publicKey)) { + throw new SodiumException('Public key has small order'); + } /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */ $A = ParagonIE_Sodium_Core32_Ed25519::ge_frombytes_negate_vartime($publicKey); + if (!ParagonIE_Sodium_Core32_Ed25519::is_on_main_subgroup($A)) { + throw new SodiumException('Public key is not on a member of the main subgroup'); + } $hs = hash_init('sha512'); self::hash_update($hs, self::substr($sig, 0, 32));