diff --git a/phpseclib/File/Traits/Extensions.php b/phpseclib/File/Traits/Extensions.php deleted file mode 100644 index 8705745d..00000000 --- a/phpseclib/File/Traits/Extensions.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @copyright 2012 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -namespace phpseclib3\File\Traits; - -trait Extensions -{ - /** - * @var array - * @access private - */ - private static $extensions = []; - - /** - * @var array - * @access private - */ - private $extensionValues = []; - - /** - * Register the mapping for a custom/unsupported extension. - * - * @param string $id - * @param array $mapping - */ - public static function registerExtension($id, array $mapping) - { - self::$extensions[$id] = $mapping; - } - - /** - * Register the mapping for a custom/unsupported extension. - * - * @param string $id - * @param mixed $value - */ - public function setExtensionValue($id, $value) - { - $this->extensionValues[$id] = $value; - } -} diff --git a/phpseclib/File/X509.php b/phpseclib/File/X509.php index 51bf4c81..57dbf052 100644 --- a/phpseclib/File/X509.php +++ b/phpseclib/File/X509.php @@ -54,8 +54,6 @@ use phpseclib3\Math\BigInteger; */ class X509 { - use Extensions; - /** * Flag to only accept signatures signed by certificate authorities * @@ -270,6 +268,12 @@ class X509 */ private $challenge; + /** + * @var array + * @access private + */ + private $extensionValues = []; + /** * OIDs loaded * @@ -294,6 +298,12 @@ class X509 */ private static $disable_url_fetch = false; + /** + * @var array + * @access private + */ + private static $extensions = []; + /** * Default Constructor. * @@ -4014,4 +4024,44 @@ class X509 return false; } + + /** + * Register the mapping for a custom/unsupported extension. + * + * @param string $id + * @param array $mapping + */ + public static function registerExtension($id, array $mapping) + { + if (isset(self::$extensions[$id]) && self::$extensions[$id] !== $mapping) { + throw new \RuntimeException( + 'Extension ' . $id . ' has already been defined with a different mapping.' + ); + } + + self::$extensions[$id] = $mapping; + } + + /** + * Register the mapping for a custom/unsupported extension. + * + * @param string $id + * + * @return array|null + */ + public static function getRegisteredExtension($id) + { + return isset(self::$extensions[$id]) ? self::$extensions[$id] : null; + } + + /** + * Register the mapping for a custom/unsupported extension. + * + * @param string $id + * @param mixed $value + */ + public function setExtensionValue($id, $value) + { + $this->extensionValues[$id] = $value; + } } diff --git a/tests/Unit/File/X509/X509ExtensionTest.php b/tests/Unit/File/X509/X509ExtensionTest.php index 781a75db..4613d9e3 100644 --- a/tests/Unit/File/X509/X509ExtensionTest.php +++ b/tests/Unit/File/X509/X509ExtensionTest.php @@ -21,12 +21,7 @@ class Unit_File_X509_X509ExtensionTest extends PhpseclibTestCase ]; $customExtensionName = 'cust'; $customExtensionNumber = '2.16.840.1.101.3.4.2.99'; - - ASN1::loadOIDs([ - $customExtensionName => $customExtensionNumber, - ]); - - X509::registerExtension($customExtensionName, [ + $customExtensionMapping = [ 'type' => ASN1::TYPE_SEQUENCE, 'children' => [ 'toggle' => ['type' => ASN1::TYPE_BOOLEAN], @@ -39,8 +34,14 @@ class Unit_File_X509_X509ExtensionTest extends PhpseclibTestCase 'children' => ['type' => ASN1::TYPE_OCTET_STRING], ], ], + ]; + + ASN1::loadOIDs([ + $customExtensionName => $customExtensionNumber, ]); + X509::registerExtension($customExtensionName, $customExtensionMapping); + $privateKey = RSA::createKey(); $publicKey = $privateKey->getPublicKey(); @@ -79,5 +80,38 @@ class Unit_File_X509_X509ExtensionTest extends PhpseclibTestCase $this->assertSame('3', (string) $customExtensionDecodedData['num']); $this->assertSame('Johnny', $customExtensionDecodedData['name']); $this->assertSame(['foo', 'bar'], $customExtensionDecodedData['list']); + $this->assertSame($customExtensionMapping, X509::getRegisteredExtension($customExtensionName)); + } + + public function testCustomExtensionRegisterTwiceTheSame() + { + $customExtensionMapping = [ + 'type' => ASN1::TYPE_SEQUENCE, + 'children' => [ + 'toggle' => ['type' => ASN1::TYPE_BOOLEAN], + 'num' => ['type' => ASN1::TYPE_INTEGER], + 'name' => ['type' => ASN1::TYPE_OCTET_STRING], + 'list' => [ + 'type' => ASN1::TYPE_SEQUENCE, + 'min' => 0, + 'max' => -1, + 'children' => ['type' => ASN1::TYPE_OCTET_STRING], + ], + ], + ]; + + X509::registerExtension('foo', $customExtensionMapping); + X509::registerExtension('foo', $customExtensionMapping); + + $this->assertSame($customExtensionMapping, X509::getRegisteredExtension('foo')); + } + + public function testCustomExtensionRegisterConflict() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Extension bar has already been defined with a different mapping.'); + + X509::registerExtension('bar', ['type' => ASN1::TYPE_OCTET_STRING]); + X509::registerExtension('bar', ['type' => ASN1::TYPE_ANY]); } }