CVE-2023-27560: Loop with Unreachable Exit Condition ('Infinite Loop') (CWE-835)
value: Math/PrimeField.php in phpseclib 3.x before 3.0.19 has an infinite loop with composite primefields.
CWE description: The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
CVSS v3 base score: 7.5
Published: 2023-03-03T06:15Z
Repository: https://github.com/phpseclib/phpseclib
Language: PHP
Files changed: phpseclib/Math/PrimeField.php, phpseclib/Math/PrimeField/Integer.php
Commit date: 2023-03-02 03:25:08 -0600
Commit message: PrimeField: prevent infinite loop with composite primefields

Diff: diff --git a/phpseclib/Math/PrimeField.php b/phpseclib/Math/PrimeField.php
index 17ff87a0..1a0667f0 100644
--- a/phpseclib/Math/PrimeField.php
+++ b/phpseclib/Math/PrimeField.php
@@ -42,13 +42,13 @@ class PrimeField extends FiniteField
     /**
      * Default constructor
      */
     public function __construct(BigInteger $modulo)
     {
-        //if (!$modulo->isPrime()) {
-        //    throw new \UnexpectedValueException('PrimeField requires a prime number be passed to the constructor');
-        //}
+        if (!$modulo->isPrime()) {
+            throw new \UnexpectedValueException('PrimeField requires a prime number be passed to the constructor');
+        }
 
         $this->instanceID = self::$instanceCounter++;
         Integer::setModulo($this->instanceID, $modulo);
         Integer::setRecurringModuloFunction($this->instanceID, $modulo->createRecurringModuloFunction());
     }
diff --git a/phpseclib/Math/PrimeField/Integer.php b/phpseclib/Math/PrimeField/Integer.php
index 2d0c10ca..748f9a49 100644
--- a/phpseclib/Math/PrimeField/Integer.php
+++ b/phpseclib/Math/PrimeField/Integer.php
@@ -261,17 +261,17 @@ class Integer extends Base
         $t = $this->value->powMod($q, static::$modulo[$this->instanceID]);
         list($temp) = $q->add($one)->divide($two);
         $r = $this->value->powMod($temp, static::$modulo[$this->instanceID]);
 
         while (!$t->equals($one)) {
-            $i = clone $one;
-
-            while (!$t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) {
-                $i = $i->add($one);
+            for ($i == clone $one; $i->compare($m) < 0; $i = $i->add($one)) {
+                if ($t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) {
+                    break;
+                }
             }
 
-            if ($i->compare($m) >= 0) {
+            if ($i->compare($m) == 0) {
                 return false;
             }
             $b = $c->powMod($two->pow($m->subtract($i)->subtract($one)), static::$modulo[$this->instanceID]);
             $m = $i;
             $c = $reduce($b->multiply($b));

Vulnerable code:         //if (!$modulo->isPrime()) {
        //    throw new \UnexpectedValueException('PrimeField requires a prime number be passed to the constructor');
        //}
            $i = clone $one;

            while (!$t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) {
                $i = $i->add($one);
            if ($i->compare($m) >= 0) {
Fixed code:         if (!$modulo->isPrime()) {
            throw new \UnexpectedValueException('PrimeField requires a prime number be passed to the constructor');
        }
            for ($i == clone $one; $i->compare($m) < 0; $i = $i->add($one)) {
                if ($t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) {
                    break;
                }
            if ($i->compare($m) == 0) {