From b90c33200e20c786fbe7c2acff2e35729a71af59 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Fri, 2 Apr 2021 10:43:15 -0500 Subject: [PATCH 01/21] ASN1: don't allow last octet in OID to have MSB set --- phpseclib/File/ASN1.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php index 00c913b8..13975ab7 100644 --- a/phpseclib/File/ASN1.php +++ b/phpseclib/File/ASN1.php @@ -517,6 +517,9 @@ class File_ASN1 break; case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: $current['content'] = $this->_decodeOID(substr($content, $content_pos)); + if ($current['content'] === false) { + return false; + } break; /* Each character string type shall be encoded as if it had been declared: [UNIVERSAL x] IMPLICIT OCTET STRING @@ -1228,6 +1231,11 @@ class File_ASN1 $oid = array(); $pos = 0; $len = strlen($content); + + if (ord($content[$len - 1]) & 0x80) { + return false; + } + $n = new Math_BigInteger(); while ($pos < $len) { $temp = ord($content[$pos++]); From 95f597cfb30e118236252884548b4c0be4320907 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Fri, 2 Apr 2021 13:46:14 -0500 Subject: [PATCH 02/21] ASN1: tweaks to tag decoding --- phpseclib/File/ASN1.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php index 13975ab7..8785c061 100644 --- a/phpseclib/File/ASN1.php +++ b/phpseclib/File/ASN1.php @@ -317,7 +317,7 @@ class File_ASN1 $current = array('start' => $start); $type = ord($encoded[$encoded_pos++]); - $start++; + $startOffset = 1; $constructed = ($type >> 5) & 1; @@ -327,13 +327,20 @@ class File_ASN1 // process septets (since the eighth bit is ignored, it's not an octet) do { $temp = ord($encoded[$encoded_pos++]); + $startOffset++; $loop = $temp >> 7; $tag <<= 7; - $tag |= $temp & 0x7F; - $start++; + $temp &= 0x7F; + // "bits 7 to 1 of the first subsequent octet shall not all be zero" + if ($startOffset == 2 && $temp == 0) { + return false; + } + $tag |= $temp; } while ($loop); } + $start+= $startOffset; + // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13 $length = ord($encoded[$encoded_pos++]); $start++; From a589442a78d9d7a52cb8312e8d44b8c40178864d Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 11:07:25 -0500 Subject: [PATCH 03/21] ASN1: uncomment out extra validation code --- phpseclib/File/ASN1.php | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php index 8785c061..a5369784 100644 --- a/phpseclib/File/ASN1.php +++ b/phpseclib/File/ASN1.php @@ -433,9 +433,9 @@ class File_ASN1 switch ($tag) { case FILE_ASN1_TYPE_BOOLEAN: // "The contents octets shall consist of a single octet." -- paragraph 8.2.1 - //if (strlen($content) != 1) { - // return false; - //} + if (strlen($content) != 1) { + return false; + } $current['content'] = (bool) ord($content[$content_pos]); break; case FILE_ASN1_TYPE_INTEGER: @@ -459,15 +459,15 @@ class File_ASN1 $last = count($temp) - 1; for ($i = 0; $i < $last; $i++) { // all subtags should be bit strings - //if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) { - // return false; - //} + if ($temp[$i]['type'] != FILE_ASN1_TYPE_BIT_STRING) { + return false; + } $current['content'].= substr($temp[$i]['content'], 1); } // all subtags should be bit strings - //if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) { - // return false; - //} + if ($temp[$last]['type'] != FILE_ASN1_TYPE_BIT_STRING) { + return false; + } $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1); } break; @@ -484,9 +484,9 @@ class File_ASN1 } $content_pos += $temp['length']; // all subtags should be octet strings - //if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) { - // return false; - //} + if ($temp['type'] != FILE_ASN1_TYPE_OCTET_STRING) { + return false; + } $current['content'].= $temp['content']; $length+= $temp['length']; } @@ -497,9 +497,9 @@ class File_ASN1 break; case FILE_ASN1_TYPE_NULL: // "The contents octets shall not contain any octets." -- paragraph 8.8.2 - //if (strlen($content)) { - // return false; - //} + if (strlen($content)) { + return false; + } break; case FILE_ASN1_TYPE_SEQUENCE: case FILE_ASN1_TYPE_SET: From 42fc46e9a92c2ce5b10d2fbfb00b630417d6dfbe Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 11:33:49 -0500 Subject: [PATCH 04/21] RSA: make sure that parameters is null for relaxed PKCS1 signatures --- phpseclib/Crypt/RSA/PublicKey.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/phpseclib/Crypt/RSA/PublicKey.php b/phpseclib/Crypt/RSA/PublicKey.php index 3475ad99..ac25e2e5 100644 --- a/phpseclib/Crypt/RSA/PublicKey.php +++ b/phpseclib/Crypt/RSA/PublicKey.php @@ -188,6 +188,10 @@ class PublicKey extends RSA implements Common\PublicKey return false; } + if (isset($decoded['digestAlgorithm']['parameters']) && $decoded['digestAlgorithm']['parameters'] !== ['null' => '']) { + return false; + } + $hash = $decoded['digestAlgorithm']['algorithm']; $hash = substr($hash, 0, 3) == 'id-' ? substr($hash, 3) : From dbd210c4a7ffc652a15792ed83125a6f93306a80 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 11:38:11 -0500 Subject: [PATCH 05/21] Tests/ASN1: add test for null garbage bytes --- tests/Unit/File/ASN1Test.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Unit/File/ASN1Test.php b/tests/Unit/File/ASN1Test.php index 00ee7c8e..eda3ea36 100644 --- a/tests/Unit/File/ASN1Test.php +++ b/tests/Unit/File/ASN1Test.php @@ -392,4 +392,17 @@ class Unit_File_ASN1Test extends PhpseclibTestCase $this->assertIsArray($a); } + + public function testNullGarbage() + { + $asn1 = new File_ASN1(); + + $em = pack('H*', '3080305c0609608648016503040201054f8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888804207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + + $em = pack('H*', '3080307f0609608648016503040201057288888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888804207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca90000'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + } } From 6be326e7e7c73c472839bd446b42aa834dcbe5df Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 12:04:07 -0500 Subject: [PATCH 06/21] Tests/ASN1: add test for OID garbage bytes --- tests/Unit/File/ASN1Test.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Unit/File/ASN1Test.php b/tests/Unit/File/ASN1Test.php index eda3ea36..84384b2c 100644 --- a/tests/Unit/File/ASN1Test.php +++ b/tests/Unit/File/ASN1Test.php @@ -405,4 +405,17 @@ class Unit_File_ASN1Test extends PhpseclibTestCase $decoded = $asn1->decodeBER($em); $this->assertFalse($decoded[0]); } + + public function testOIDGarbage() + { + $asn1 = new File_ASN1(); + + $em = pack('H*', '3080305c065860864801650304020188888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888050004207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + + $em = pack('H*', '3080307f067d608648016503040201888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888804207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + } } From 8b8cbecb9b97f4b7aa60a45aea828e3c563b897d Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 13:15:58 -0500 Subject: [PATCH 07/21] ASN1: make sure constructed bit is what it ought to be --- phpseclib/File/ASN1.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php index a5369784..2424d341 100644 --- a/phpseclib/File/ASN1.php +++ b/phpseclib/File/ASN1.php @@ -433,13 +433,16 @@ class File_ASN1 switch ($tag) { case FILE_ASN1_TYPE_BOOLEAN: // "The contents octets shall consist of a single octet." -- paragraph 8.2.1 - if (strlen($content) != 1) { + if ($constructed || strlen($content) != 1) { return false; } $current['content'] = (bool) ord($content[$content_pos]); break; case FILE_ASN1_TYPE_INTEGER: case FILE_ASN1_TYPE_ENUMERATED: + if ($constructed) { + return false; + } $current['content'] = new Math_BigInteger(substr($content, $content_pos), -256); break; case FILE_ASN1_TYPE_REAL: // not currently supported @@ -497,12 +500,15 @@ class File_ASN1 break; case FILE_ASN1_TYPE_NULL: // "The contents octets shall not contain any octets." -- paragraph 8.8.2 - if (strlen($content)) { + if ($constructed || strlen($content)) { return false; } break; case FILE_ASN1_TYPE_SEQUENCE: case FILE_ASN1_TYPE_SET: + if (!$constructed) { + return false; + } $offset = 0; $current['content'] = array(); $content_len = strlen($content); @@ -523,6 +529,9 @@ class File_ASN1 } break; case FILE_ASN1_TYPE_OBJECT_IDENTIFIER: + if ($constructed) { + return false; + } $current['content'] = $this->_decodeOID(substr($content, $content_pos)); if ($current['content'] === false) { return false; @@ -556,10 +565,16 @@ class File_ASN1 case FILE_ASN1_TYPE_UTF8_STRING: // ???? case FILE_ASN1_TYPE_BMP_STRING: + if ($constructed) { + return false; + } $current['content'] = substr($content, $content_pos); break; case FILE_ASN1_TYPE_UTC_TIME: case FILE_ASN1_TYPE_GENERALIZED_TIME: + if ($constructed) { + return false; + } $current['content'] = class_exists('DateTime') ? $this->_decodeDateTime(substr($content, $content_pos), $tag) : $this->_decodeUnixTime(substr($content, $content_pos), $tag); From 730070b78f08e83c2edd65d8c6a03c9da3b8b277 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 13:25:56 -0500 Subject: [PATCH 08/21] Tests/ASN1: update unit tests to work on 2.0 branch --- tests/Unit/File/ASN1Test.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/File/ASN1Test.php b/tests/Unit/File/ASN1Test.php index 35bf877f..7b9d0943 100644 --- a/tests/Unit/File/ASN1Test.php +++ b/tests/Unit/File/ASN1Test.php @@ -395,7 +395,7 @@ class Unit_File_ASN1Test extends PhpseclibTestCase public function testNullGarbage() { - $asn1 = new File_ASN1(); + $asn1 = new ASN1(); $em = pack('H*', '3080305c0609608648016503040201054f8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888804207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); $decoded = $asn1->decodeBER($em); @@ -408,7 +408,7 @@ class Unit_File_ASN1Test extends PhpseclibTestCase public function testOIDGarbage() { - $asn1 = new File_ASN1(); + $asn1 = new ASN1(); $em = pack('H*', '3080305c065860864801650304020188888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888050004207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); $decoded = $asn1->decodeBER($em); From c1d21edb94793ba1093e3df3a7ea4ee9a59a382b Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 13:44:29 -0500 Subject: [PATCH 09/21] Tests/ASN1: add tests for constructed mismatches --- tests/Unit/File/ASN1Test.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Unit/File/ASN1Test.php b/tests/Unit/File/ASN1Test.php index 84384b2c..2a5ad9ea 100644 --- a/tests/Unit/File/ASN1Test.php +++ b/tests/Unit/File/ASN1Test.php @@ -418,4 +418,25 @@ class Unit_File_ASN1Test extends PhpseclibTestCase $decoded = $asn1->decodeBER($em); $this->assertFalse($decoded[0]); } + + public function testConstructedMismatch() + { + $asn1 = new File_ASN1(); + + $em = pack('H*', '1031300d0609608648016503040201050004207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + + $em = pack('H*', '3031100d0609608648016503040201050004207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + + $em = pack('H*', '3031300d2609608648016503040201050004207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + + $em = pack('H*', '3031300d06096086480165030402012d0004207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + } } From 0fc7c81c66f39355e5488820ffa16121fd3f9eb2 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 13:48:40 -0500 Subject: [PATCH 10/21] fix bad merge --- phpseclib/File/ASN1.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php index 5242ef3a..0edd61e8 100644 --- a/phpseclib/File/ASN1.php +++ b/phpseclib/File/ASN1.php @@ -452,14 +452,10 @@ abstract class ASN1 } break; case self::TYPE_OBJECT_IDENTIFIER: -<<<<<<< HEAD - $current['content'] = self::decodeOID(substr($content, $content_pos)); -======= if ($constructed) { return false; } - $current['content'] = $this->_decodeOID(substr($content, $content_pos)); ->>>>>>> moosa-2.0 + $current['content'] = self::decodeOID(substr($content, $content_pos)); if ($current['content'] === false) { return false; } From 10cee4514cc9d160d4cd22378ec168415d483ea3 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 13:53:20 -0500 Subject: [PATCH 11/21] Tests/ASN1: test for bad tag --- tests/Unit/File/ASN1Test.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Unit/File/ASN1Test.php b/tests/Unit/File/ASN1Test.php index 2a5ad9ea..747e3c9a 100644 --- a/tests/Unit/File/ASN1Test.php +++ b/tests/Unit/File/ASN1Test.php @@ -439,4 +439,13 @@ class Unit_File_ASN1Test extends PhpseclibTestCase $decoded = $asn1->decodeBER($em); $this->assertFalse($decoded[0]); } + + public function testBadTagSecondOctet() + { + $asn1 = new File_ASN1(); + + $em = pack('H*', '3033300f1f808080060960864801650304020104207509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9'); + $decoded = $asn1->decodeBER($em); + $this->assertFalse($decoded[0]); + } } From e02c8452d41f643c5d6208078f45f4b0cb6335b7 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 15:54:27 -0500 Subject: [PATCH 12/21] ASN1: fail when encountering unsupported tags --- phpseclib/File/ASN1.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php index 2424d341..1419c097 100644 --- a/phpseclib/File/ASN1.php +++ b/phpseclib/File/ASN1.php @@ -578,7 +578,9 @@ class File_ASN1 $current['content'] = class_exists('DateTime') ? $this->_decodeDateTime(substr($content, $content_pos), $tag) : $this->_decodeUnixTime(substr($content, $content_pos), $tag); + break; default: + return false; } $start+= $length; From 9af9d69c19788819ab467dce513c5941af7efc37 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 16:00:42 -0500 Subject: [PATCH 13/21] RSA: support "strict" PKCS1 sigs without NULLs --- phpseclib/Crypt/RSA.php | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index 7671e858..de3d3ed5 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -3001,6 +3001,56 @@ class Crypt_RSA return $em; } + /** + * EMSA-PKCS1-V1_5-ENCODE (without NULL) + * + * Quoting https://tools.ietf.org/html/rfc8017#page-65, + * + * "The parameters field associated with id-sha1, id-sha224, id-sha256, + * id-sha384, id-sha512, id-sha512/224, and id-sha512/256 should + * generally be omitted, but if present, it shall have a value of type + * NULL" + * + * @access private + * @param string $m + * @param int $emLen + * @return string + */ + function _emsa_pkcs1_v1_5_encode_without_null($m, $emLen) + { + $h = $this->hash->hash($m); + if ($h === false) { + return false; + } + + switch ($this->hashName) { + case 'sha1': + $t = pack('H*', '301f300706052b0e03021a0414'); + break; + case 'sha256': + $t = pack('H*', '302f300b06096086480165030402010420'); + break; + case 'sha384': + $t = pack('H*', '303f300b06096086480165030402020430'); + break; + case 'sha512': + $t = pack('H*', '304f300b06096086480165030402030440'); + } + $t.= $h; + $tLen = strlen($t); + + if ($emLen < $tLen + 11) { + user_error('Intended encoded message length too short'); + return false; + } + + $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3); + + $em = "\0\1$ps\0$t"; + + return $em; + } + /** * RSASSA-PKCS1-V1_5-SIGN * @@ -3067,13 +3117,15 @@ class Crypt_RSA // EMSA-PKCS1-v1_5 encoding $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); - if ($em2 === false) { + $em3 = $this->_emsa_pkcs1_v1_5_encode_without_null($m, $this->k); + + if ($em2 === false || $em3 === false) { user_error('RSA modulus too short'); return false; } // Compare - return $this->_equals($em, $em2); + return $this->_equals($em, $em2) || $this->_equals($em, $em3); } /** From 7a5846cceec90569451d8c53bb6443c0c724974d Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 16:13:54 -0500 Subject: [PATCH 14/21] Test/RSA: add test for "strict" PKCS1 sigs without NULLs --- tests/Unit/Crypt/RSA/ModeTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Unit/Crypt/RSA/ModeTest.php b/tests/Unit/Crypt/RSA/ModeTest.php index 28e91643..a070b3d3 100644 --- a/tests/Unit/Crypt/RSA/ModeTest.php +++ b/tests/Unit/Crypt/RSA/ModeTest.php @@ -115,4 +115,25 @@ k12yS6pCS3c+1wZ9cYFVtgfpSL4XpylLe9EnRT2GRVYCqUkR4AUeTuvnAgMBAAE= $payload = 'eyJraWQiOiJ0RkMyVUloRnBUTV9FYTNxY09kX01xUVQxY0JCbTlrRkxTRGZlSmhzUkc4IiwiYWxnIjoiUFMyNTYifQ.eyJhcHAiOiJhY2NvdW50cG9ydGFsIiwic3ViIjoiNTliOGM4YzA5NTVhNDA5MDg2MGRmYmM3ZGQwMjVjZWEiLCJjbGlkIjoiZTQ5ZTA2N2JiMTFjNDcyMmEzNGIyYjNiOGE2YTYzNTUiLCJhbSI6InBhc3N3b3JkIiwicCI6ImVOcDFrRUZQd3pBTWhmXC9QdEVOYU5kQkc2bUZDNHNpbENNNXU0aTNXMHFSS0hFVDU5V1JzcXpZRUp4XC84M3ZQbkIxcUg3Rm5CZVNabEtNME9saGVZVUVWTXlHOEVUOEZnWDI4dkdqWG4wWkcrV2hSK01rWVBicGZacHI2U3E0N0RFYjBLYkRFT21CSUZuOTZKN1ZDaWg1Q2p4dWNRZDJmdHJlMCt2cSthZFFObUluK0poWEl0UlBvQ0xya1wvZ05VV3N3T09vSVwva0Q5ZVk4c05jRHFPUzNkanFWb3RPU21oRUo5b0hZZmFqZmpSRzFGSWpGRFwvOExtT2pKbVF3d0tBMnQ0aXJBQ2NncHo0dzBuN3BtXC84YXV2T0dFM2twVFZ2d0IzdzlQZk1YZnJJUTBhejRsaEtIdVBUMU42XC9sb1FJPSIsImlhaSI6IjU5YjhjOGMwOTU1YTQwOTA4NjBkZmJjN2RkMDI1Y2VhIiwiY2xzdmMiOiJhY2NvdW50cG9ydGFsIiwibHB2IjoxNTQ3Njc1NDM4LCJ0IjoicyIsImljIjp0cnVlLCJleHAiOjE1NDc3MDQyMzgsImlhdCI6MTU0NzY3NTQzOCwianRpIjoiZTE0N2UzM2UzNzVhNDkyNWJjMzdjZTRjMDIwMmJjNDYifQ'; $this->assertTrue($rsa->verify($payload, $sig)); } + + public function testPKCS1SigWithoutNull() + { + $rsa = new Crypt_RSA(); + $rsa->loadKey(array( + 'n' => new Math_BigInteger('0xE932AC92252F585B3A80A4DD76A897C8B7652952FE788F6EC8DD640587A1EE5647670A8AD +4C2BE0F9FA6E49C605ADF77B5174230AF7BD50E5D6D6D6D28CCF0A886A514CC72E51D209CC7 +72A52EF419F6A953F3135929588EBE9B351FCA61CED78F346FE00DBB6306E5C2A4C6DFC3779 +AF85AB417371CF34D8387B9B30AE46D7A5FF5A655B8D8455F1B94AE736989D60A6F2FD5CADB +FFBD504C5A756A2E6BB5CECC13BCA7503F6DF8B52ACE5C410997E98809DB4DC30D943DE4E81 +2A47553DCE54844A78E36401D13F77DC650619FED88D8B3926E3D8E319C80C744779AC5D6AB +E252896950917476ECE5E8FC27D5F053D6018D91B502C4787558A002B9283DA7', 16), + 'e' => new Math_BigInteger('3') + )); + + $message = 'hello world!'; + $signature = pack('H*', 'a0073057133ff3758e7e111b4d7441f1d8cbe4b2dd5ee4316a14264290dee5ed7f175716639bd9bb43a14e4f9fcb9e84dedd35e2205caac04828b2c053f68176d971ea88534dd2eeec903043c3469fc69c206b2a8694fd262488441ed8852280c3d4994e9d42bd1d575c7024095f1a20665925c2175e089c0d731471f6cc145404edf5559fd2276e45e448086f71c78d0cc6628fad394a34e51e8c10bc39bfe09ed2f5f742cc68bee899d0a41e4c75b7b80afd1c321d89ccd9fe8197c44624d91cc935dfa48de3c201099b5b417be748aef29248527e8bbb173cab76b48478d4177b338fe1f1244e64d7d23f07add560d5ad50b68d6649a49d7bc3db686daaa7'); + + $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); + $this->assertTrue($rsa->verify($message, $signature)); + } } From 4a3e08c2733a40de94ee82c21085c915cc667f7e Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 16:33:23 -0500 Subject: [PATCH 15/21] RSA: tweak to new validation method --- phpseclib/Crypt/RSA.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index de3d3ed5..770c6747 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -3119,7 +3119,7 @@ class Crypt_RSA $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); $em3 = $this->_emsa_pkcs1_v1_5_encode_without_null($m, $this->k); - if ($em2 === false || $em3 === false) { + if ($em2 === false && $em3 === false) { user_error('RSA modulus too short'); return false; } From 5fca2bcb7b2cc57651f18cd6d3f469c905a185b0 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 16:33:52 -0500 Subject: [PATCH 16/21] Tests/RSA: test requires sha256 --- tests/Unit/Crypt/RSA/ModeTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/Crypt/RSA/ModeTest.php b/tests/Unit/Crypt/RSA/ModeTest.php index a070b3d3..021352a1 100644 --- a/tests/Unit/Crypt/RSA/ModeTest.php +++ b/tests/Unit/Crypt/RSA/ModeTest.php @@ -134,6 +134,7 @@ E252896950917476ECE5E8FC27D5F053D6018D91B502C4787558A002B9283DA7', 16), $signature = pack('H*', 'a0073057133ff3758e7e111b4d7441f1d8cbe4b2dd5ee4316a14264290dee5ed7f175716639bd9bb43a14e4f9fcb9e84dedd35e2205caac04828b2c053f68176d971ea88534dd2eeec903043c3469fc69c206b2a8694fd262488441ed8852280c3d4994e9d42bd1d575c7024095f1a20665925c2175e089c0d731471f6cc145404edf5559fd2276e45e448086f71c78d0cc6628fad394a34e51e8c10bc39bfe09ed2f5f742cc68bee899d0a41e4c75b7b80afd1c321d89ccd9fe8197c44624d91cc935dfa48de3c201099b5b417be748aef29248527e8bbb173cab76b48478d4177b338fe1f1244e64d7d23f07add560d5ad50b68d6649a49d7bc3db686daaa7'); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); + $rsa->setHash('sha256'); $this->assertTrue($rsa->verify($message, $signature)); } } From 581fbdb67195c1a578e21b497973e6a0e4168b15 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 16:41:10 -0500 Subject: [PATCH 17/21] CS adjustments --- tests/Unit/Crypt/RSA/ModeTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Crypt/RSA/ModeTest.php b/tests/Unit/Crypt/RSA/ModeTest.php index 021352a1..e900be3d 100644 --- a/tests/Unit/Crypt/RSA/ModeTest.php +++ b/tests/Unit/Crypt/RSA/ModeTest.php @@ -120,14 +120,14 @@ k12yS6pCS3c+1wZ9cYFVtgfpSL4XpylLe9EnRT2GRVYCqUkR4AUeTuvnAgMBAAE= { $rsa = new Crypt_RSA(); $rsa->loadKey(array( - 'n' => new Math_BigInteger('0xE932AC92252F585B3A80A4DD76A897C8B7652952FE788F6EC8DD640587A1EE5647670A8AD + 'n' => new Math_BigInteger('0xE932AC92252F585B3A80A4DD76A897C8B7652952FE788F6EC8DD640587A1EE5647670A8AD 4C2BE0F9FA6E49C605ADF77B5174230AF7BD50E5D6D6D6D28CCF0A886A514CC72E51D209CC7 72A52EF419F6A953F3135929588EBE9B351FCA61CED78F346FE00DBB6306E5C2A4C6DFC3779 AF85AB417371CF34D8387B9B30AE46D7A5FF5A655B8D8455F1B94AE736989D60A6F2FD5CADB FFBD504C5A756A2E6BB5CECC13BCA7503F6DF8B52ACE5C410997E98809DB4DC30D943DE4E81 2A47553DCE54844A78E36401D13F77DC650619FED88D8B3926E3D8E319C80C744779AC5D6AB E252896950917476ECE5E8FC27D5F053D6018D91B502C4787558A002B9283DA7', 16), - 'e' => new Math_BigInteger('3') + 'e' => new Math_BigInteger('3') )); $message = 'hello world!'; From d70abb929005b419cd911cfd45738c2a1bfd6f50 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 17:13:19 -0500 Subject: [PATCH 18/21] fix broken unit test --- tests/Unit/Crypt/RSA/ModeTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/Crypt/RSA/ModeTest.php b/tests/Unit/Crypt/RSA/ModeTest.php index 2763df29..854f9082 100644 --- a/tests/Unit/Crypt/RSA/ModeTest.php +++ b/tests/Unit/Crypt/RSA/ModeTest.php @@ -6,6 +6,7 @@ */ use phpseclib\Crypt\RSA; +use phpseclib\Math\BigInteger; class Unit_Crypt_RSA_ModeTest extends PhpseclibTestCase { From f61cce9c834fb39127abe94d94d30ec6378632aa Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 17:50:28 -0500 Subject: [PATCH 19/21] RSA: misc fixes for "without NULL" PKCS1 signature validation --- phpseclib/Crypt/RSA.php | 3 +++ phpseclib/Crypt/RSA/PublicKey.php | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index ad416945..3d343dc6 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -660,6 +660,9 @@ abstract class RSA extends AsymmetricKey break; case 'sha512/256': $t = "\x30\x2f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x04\x20"; + break; + default: + throw new UnsupportedAlgorithmException('md2 and md5 require NULLs'); } $t.= $h; $tLen = strlen($t); diff --git a/phpseclib/Crypt/RSA/PublicKey.php b/phpseclib/Crypt/RSA/PublicKey.php index e6afa49b..1d046bcc 100644 --- a/phpseclib/Crypt/RSA/PublicKey.php +++ b/phpseclib/Crypt/RSA/PublicKey.php @@ -20,6 +20,7 @@ use phpseclib3\Common\Functions\Strings; use phpseclib3\Crypt\Hash; use phpseclib3\Exception\NoKeyLoadedException; use phpseclib3\Exception\UnsupportedFormatException; +use phpseclib3\Exception\UnsupportedAlgorithmException; use phpseclib3\Crypt\Random; use phpseclib3\Crypt\Common; use phpseclib3\File\ASN1\Maps\DigestInfo; @@ -103,14 +104,18 @@ class PublicKey extends RSA implements Common\PublicKey // too short" and stop. try { $em2 = $this->emsa_pkcs1_v1_5_encode($m, $this->k); + $r1 = hash_equals($em, $em2); } catch (\LengthException $e) { $exception = true; } try { - $em3 = $this->emsa_pkcs1_v1_5_encode_witout_null($m, $this->k); + $em3 = $this->emsa_pkcs1_v1_5_encode_without_null($m, $this->k); + $r2 = hash_equals($em, $em3); } catch (\LengthException $e) { $exception = true; + } catch (UnsupportedAlgorithmException $e) { + $r2 = false; } if ($exception) { @@ -118,7 +123,7 @@ class PublicKey extends RSA implements Common\PublicKey } // Compare - return hash_equals($em, $em2) || hash_equals($em, $em3); + return $r1 || $r2; } /** From 8af4280bdebf77b87b558510c925794380b84d16 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 17:55:12 -0500 Subject: [PATCH 20/21] RSA: misc fixes for 'without NULL' PKCS1 signature validation --- phpseclib/Crypt/RSA.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index 770c6747..c5f69770 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -3035,6 +3035,9 @@ class Crypt_RSA break; case 'sha512': $t = pack('H*', '304f300b06096086480165030402030440'); + break; + default: + return false; } $t.= $h; $tLen = strlen($t); From 149b4d213131d4d453fe190700a4ecc3d09de9cc Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 3 Apr 2021 18:16:59 -0500 Subject: [PATCH 21/21] RSA: fix for PHP8 --- phpseclib/Crypt/RSA.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index c5f69770..49a61f3b 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -3128,7 +3128,9 @@ class Crypt_RSA } // Compare - return $this->_equals($em, $em2) || $this->_equals($em, $em3); + + return ($em2 !== false && $this->_equals($em, $em2)) || + ($em3 !== false && $this->_equals($em, $em3)); } /**