jose-php icon indicating copy to clipboard operation
jose-php copied to clipboard

Changed version phpseclib 3

Open darkdim opened this issue 4 years ago • 9 comments

Error: Class 'phpseclib\Crypt\RSA' not found in JOSE_JWK->toKey() (line 23 of \vendor\gree\jose\src\JOSE\JWK.php).

darkdim avatar Jan 20 '21 12:01 darkdim

"require": { "php": ">=5.6", "phpseclib/phpseclib": ">=2.0.0" }, in new ver phpseclib used NS as phpseclib3 need to limit ver phpseclib

darkdim avatar Jan 20 '21 12:01 darkdim

As a temporary workaround you can do that in your own project with

composer require phpseclib/phpseclib:^2.0

benjy avatar Feb 02 '21 09:02 benjy

composer require phpseclib/phpseclib2_compat:~1.0 should also work. That'd let you use the phpseclib v2 API with phpseclib v3

terrafrost avatar Feb 02 '21 12:02 terrafrost

Limiting the version to v2

composer require phpseclib/phpseclib:~2.0

Also phpseclib2_compat did not work for me

$rsa = new RSA();
$rsa->_convertPublicKey($n, $e) // method not found

nextofblake avatar Mar 02 '21 22:03 nextofblake

@NextOfBlake - the presence of the underscore means that that method is not an officially supported method. This can be traced back to the old PEAR coding standards. Quoting them, "Private class members are preceded by a single underscore".

phpseclib 3 doesn't follow this convention but phpseclib 1/2 did.

Anyway, I'd rewrite your code thusly:

$rsa = new RSA;
$rsa->load([
    'e' => new BigInteger('...'),
    'n' => new BigInteger('...')
]);

phpseclib 2 has supported this since the initial release of 2.0 (2.0.0).

terrafrost avatar Mar 03 '21 15:03 terrafrost

@terrafrost thanks for the tip however the issue is specific to this package. inspect jose-php/src/JOSE/JWK.php

function toKey() {
... stuff
$pem_string = $rsa->_convertPublicKey($n, $e);
}

nextofblake avatar Mar 03 '21 16:03 nextofblake

I wrote an override class that addresses most of not all the compatibility issues. Note that it depends on Firebase\JWT to facilitate what RSA::_convertPublicKey() previously offered. And that some Reflection hackery was needed to regain access to now-protected properties.

<?php

namespace App\Overrides\JOSE;

use Error;
use JOSE_JWK;
use ReflectionClass;
use JOSE_URLSafeBase64;
use ReflectionException;
use phpseclib3\Crypt\RSA;
use UnexpectedValueException;
use phpseclib3\Crypt\RSA\PublicKey;
use Firebase\JWT\JWK as FirebaseJWK;
use phpseclib3\Crypt\PublicKeyLoader;
use JOSE_Exception_UnexpectedAlgorithm;

/**
 * Override to cope with changes from phpseclib/phpseclib v2 to 3
 */
class JWK extends JOSE_JWK
{
    /**
     * @inheritDoc
     * @throws ReflectionException
     */
    public static function encode($key, $extra_components = [])
    {
        try {
            return parent::encode($key, $extra_components);
        } catch (JOSE_Exception_UnexpectedAlgorithm $error) {
            //
        }

        if ($key instanceof RSA\PublicKey) {
            $modulus = static::getProtectedProperty($key, 'modulus');
            $exponent = static::getProtectedProperty($key, 'exponent');

            $components = [
                'kty' => 'RSA',
                'e' => JOSE_URLSafeBase64::encode($key->publicExponent->toBytes()),
                'n' => JOSE_URLSafeBase64::encode($modulus->toBytes())
            ];

            if ($exponent != $key->publicExponent) {
                $components = array_merge($components, ['d' => JOSE_URLSafeBase64::encode($exponent->toBytes())]);
            }

            return new static(array_merge($components, $extra_components));
        }

        throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type: '.get_class($key));
    }

    /**
     * @param object $object
     * @param string $propertyName
     * @return mixed
     * @throws ReflectionException
     */
    protected static function getProtectedProperty(object $object, string $propertyName)
    {
        $reflectionClass = app(ReflectionClass::class, ['argument' => $object]);
        $reflectionProperty = $reflectionClass->getProperty($propertyName);

        if ($reflectionProperty->isPublic()) {
            throw new UnexpectedValueException($reflectionClass->name."::$propertyName is public");
        }

        $reflectionProperty->setAccessible(true);

        return $reflectionProperty->getValue($object);
    }

    /**
     * @inheritDoc
     */
    public static function decode($components)
    {
        $jwk = new static($components);

        return $jwk->toKey();
    }

    /**
     * @inheritDoc
     */
    public function toKey()
    {
        try {
            return parent::toKey();
        } catch (Error $e) {
            //
        }

        switch ($this->components['kty']) {
            case 'RSA':
                $pemResource = FirebaseJWK::parseKey($this->components);
                $keyData = openssl_pkey_get_details($pemResource);
                $keyString = $keyData['key'];

                /** @var PublicKey $rsa */
                $rsa = PublicKeyLoader::loadPublicKey($keyString);

                return $rsa;
            default:
                throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type');
        }
    }
}

kmuenkel avatar Sep 08 '21 04:09 kmuenkel

Here is my PR to change to phpseclib 3, https://github.com/nov/jose-php/pull/45

Hailong avatar Jun 17 '22 07:06 Hailong

@nov any chance to merge the PR above and release a new version ?

ilazaridis avatar Dec 19 '22 21:12 ilazaridis