CVE-2023-49316: Excessive Iteration (CWE-834)
value: In Math/BinaryField.php in phpseclib 3 before 3.0.34, excessively large degrees can lead to a denial of service.
CWE description: The product performs an iteration or loop without sufficiently limiting the number of times that the loop is executed.
CVSS v3 base score: 7.5
Published: 2023-11-27T18:15Z
Repository: https://github.com/phpseclib/phpseclib
Language: PHP
Files changed: phpseclib/Math/BinaryField.php, tests/Unit/Crypt/EC/KeyTest.php
Commit date: 2023-11-21 19:10:46 -0600
Commit message: Math/BinaryField: fix for excessively large degrees

Diff: diff --git a/phpseclib/Math/BinaryField.php b/phpseclib/Math/BinaryField.php
index 3e21a67a..5da8c937 100644
--- a/phpseclib/Math/BinaryField.php
+++ b/phpseclib/Math/BinaryField.php
@@ -46,10 +46,19 @@ class BinaryField extends FiniteField
      * Default constructor
      */
     public function __construct(...$indices)
     {
         $m = array_shift($indices);
+        if ($m > 571) {
+            /* sect571r1 and sect571k1 are the largest binary curves that https://www.secg.org/sec2-v2.pdf defines
+               altho theoretically there may be legit reasons to use binary finite fields with larger degrees
+               imposing a limit on the maximum size is both reasonable and precedented. in particular,
+               http://tools.ietf.org/html/rfc4253#section-6.1 (The Secure Shell (SSH) Transport Layer Protocol) says
+               "implementations SHOULD check that the packet length is reasonable in order for the implementation to
+                avoid denial of service and/or buffer overflow attacks" */
+            throw new \OutOfBoundsException('Degrees larger than 571 are not supported');
+        }
         $val = str_repeat('0', $m) . '1';
         foreach ($indices as $index) {
             $val[$index] = '1';
         }
         $modulo = static::base2ToBase256(strrev($val));
diff --git a/tests/Unit/Crypt/EC/KeyTest.php b/tests/Unit/Crypt/EC/KeyTest.php
index bfd1724a..adbb8f42 100644
--- a/tests/Unit/Crypt/EC/KeyTest.php
+++ b/tests/Unit/Crypt/EC/KeyTest.php
@@ -702,6 +702,22 @@ cN6W+k8UvGf+Y/lDWNbFitQocabsDUvSN0edHH3UKP5QPTz4cOlyIPMrXQ==
         $signature = 'a4f61518323bac50b4f87a0f766ebb10d1db25358a0a20a98dab20be4e9c3be2d77ff5a8415cfce2967999c73d2a49b2d8c01990f72c04d99ebe3c4ebf75b4e9';
         $signature = pack('H*', $signature);
 
         $this->assertTrue($key->verify('hello world!', $signature));
     }
+
+    public function testExcessivelyLargeBinaryField()
+    {
+        $this->expectException('\OutOfBoundsException');
+
+        $key = '-----BEGIN PUBLIC KEY-----
+MIIBDDCB0wYHKoZIzj0CATCBxwIBATAgBgcqhkjOPQECMBUCBH////8GCSqGSM49
+AQIDAgICAMEwTQQZABeFj+t6mJdRaeFx93tAh94JisipEd97AQQZAP37Sb/mw6if
+rK2qeh5bvHzBwuXYMUeIFAMVABA/rsdNaW5naHVhUXV3f8Wxke8wBDMEAfSBvF8P
++Ep0rWzfb970v2F5YlNy2MDF4QAl45nykDcSzPPqnjoa0X+wsyAbavfOGwUCGQEA
+AAAAAAAAAAAAAADH80p3j0Q6zJIOukkCAQIDNAAEAE2mUTAwdPK952h3G8ZinK8B
+z9DYTLdGkQDqox3AtEs9nn6kE1O/vHE4bqMegjj4gbA=
+-----END PUBLIC KEY-----';
+        $key = EC::loadFormat('PKCS8', $key);
+        $this->assertInstanceOf(PublicKey::class, $key);
+    }
 }

Fixed code:         if ($m > 571) {
            /* sect571r1 and sect571k1 are the largest binary curves that https://www.secg.org/sec2-v2.pdf defines
               altho theoretically there may be legit reasons to use binary finite fields with larger degrees
               imposing a limit on the maximum size is both reasonable and precedented. in particular,
               http://tools.ietf.org/html/rfc4253#section-6.1 (The Secure Shell (SSH) Transport Layer Protocol) says
               "implementations SHOULD check that the packet length is reasonable in order for the implementation to
                avoid denial of service and/or buffer overflow attacks" */
            throw new \OutOfBoundsException('Degrees larger than 571 are not supported');
        }

    public function testExcessivelyLargeBinaryField()
    {
        $this->expectException('\OutOfBoundsException');

        $key = '-----BEGIN PUBLIC KEY-----
MIIBDDCB0wYHKoZIzj0CATCBxwIBATAgBgcqhkjOPQECMBUCBH////8GCSqGSM49
AQIDAgICAMEwTQQZABeFj+t6mJdRaeFx93tAh94JisipEd97AQQZAP37Sb/mw6if
rK2qeh5bvHzBwuXYMUeIFAMVABA/rsdNaW5naHVhUXV3f8Wxke8wBDMEAfSBvF8P
+Ep0rWzfb970v2F5YlNy2MDF4QAl45nykDcSzPPqnjoa0X+wsyAbavfOGwUCGQEA
AAAAAAAAAAAAAADH80p3j0Q6zJIOukkCAQIDNAAEAE2mUTAwdPK952h3G8ZinK8B
z9DYTLdGkQDqox3AtEs9nn6kE1O/vHE4bqMegjj4gbA=
-----END PUBLIC KEY-----';
        $key = EC::loadFormat('PKCS8', $key);
        $this->assertInstanceOf(PublicKey::class, $key);
    }