8000 assert valid JWK by simonLeary42 · Pull Request #2078 · phpseclib/phpseclib · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

assert valid JWK #2078

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed

Conversation

simonLeary42
Copy link
Contributor
@simonLeary42 simonLeary42 commented Apr 19, 2025

fixes #2076, #2077

JWK::loadHelper does not do the necessary assertions on the result of json_decode. It assumes that if the key is valid JSON, then it must become an object and it must have the keys property. Because of these bad assumptions, there is an uncaught TypeError. AsymmetricKey catches any exceptions and throws NoKeyLoadedException, but errors are not exceptions.

  • Added assertions to JWK::loadHelper
  • added test cases for garbage keys
  • added @throws to docblock for PublicKeyLoader::load.

@simonLeary42 simonLeary42 marked this pull request as draft April 19, 2025 19:08
@simonLeary42
Copy link
Contributor Author

manually testing:
test-jwk-int.php:

<?php
ini_set("display_errors", 0);
require "./vendor/autoload.php";
\phpseclib3\Crypt\PublicKeyLoader::load('12345');

test-jwk-json.php:

<?php
ini_set("display_errors", 0);
require "./vendor/autoload.php";
\phpseclib3\Crypt\PublicKeyLoader::load('{"foo": "bar"}');

before:

$ (php ./test-jwk-int.php; echo ""; php ./test-jwk-json.php) 2>&1 | sed -E "s|$PWD|...|g"
PHP Warning:  Attempt to read property "keys" on int in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php on line 53
PHP Fatal error:  Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php:53
Stack trace:
#0 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php(53): count(NULL)
#1 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/JWK.php(46): phpseclib3\Crypt\Common\Formats\Keys\JWK::load(12345, false)
#2 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php(150): phpseclib3\Crypt\EC\Formats\Keys\JWK::load('12345', false)
#3 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php(39): phpseclib3\Crypt\Common\AsymmetricKey::load('12345', false)
#4 .../test-jwk-int.php(4): phpseclib3\Crypt\PublicKeyLoader::load('12345')
#5 {main}
  thrown in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php on line 53

PHP Warning:  Undefined property: stdClass::$keys in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php on line 53
PHP Fatal error:  Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php:53
Stack trace:
#0 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php(53): count(NULL)
#1 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/JWK.php(46): phpseclib3\Crypt\Common\Formats\Keys\JWK::load(Object(stdClass), false)
#2 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php(150): phpseclib3\Crypt\EC\Formats\Keys\JWK::load('{"foo": "bar"}', false)
#3 .../vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php(39): phpseclib3\Crypt\Common\AsymmetricKey::load('{"foo": "bar"}', false)
#4 .../test-jwk-json.php(4): phpseclib3\Crypt\PublicKeyLoader::load('{"foo": "bar"}')
#5 {main}
  thrown in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php on line 53

after:

$ (php ./test-jwk-int.php; echo ""; php ./test-jwk-json.php) 2>&1 | sed -E "s|$PWD|...|g"
PHP Fatal error:  Uncaught phpseclib3\Exception\NoKeyLoadedException: Unable to read key in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php:63
Stack trace:
#0 .../test-jwk-int.php(4): phpseclib3\Crypt\PublicKeyLoader::load('12345')
#1 {main}
  thrown in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php on line 63

PHP Fatal error:  Uncaught phpseclib3\Exception\NoKeyLoadedException: Unable to read key in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php:63
Stack trace:
#0 .../test-jwk-json.php(4): phpseclib3\Crypt\PublicKeyLoader::load(false)
#1 {main}
  thrown in .../vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php on line 63

@simonLeary42 simonLeary42 marked this pull request as ready for review April 19, 2025 20:37
@terrafrost
Copy link
Member

There's no reason this can't be in the 3.0 branch. To that end I thought I'd squash all your commits into one and then cherry-pick that commit into the 3.0 branch. Doing that required a few merge conflicts be resolved and when I did that here's what I got:

https://github.com/terrafrost/phpseclib/tree/bad-jwk2

The problem is that the unit tests are now failing:

https://github.com/terrafrost/phpseclib/actions/runs/14579735654/job/40893600946

  1. phpseclib3\Tests\Unit\Crypt\RSA\LoadKeyTest::testBadKey with data set #0 ('a')
    Failed asserting that exception of type "phpseclib3\Exception\NoKeyLoadedException" is thrown.

This doesn't make any sense to me. When I run the code outside of a unit test an exception is thrown as I'd expect:

<?php
include('vendor/autoload.php');

use phpseclib3\Crypt\PublicKeyLoader;

$key = 'a';
PublicKeyLoader::load($key);

At this point I'm half tempted to just remove the stupid test. I just wish I knew why it wasn't working on Github Actions...

@terrafrost
Copy link
Member

I figured out the issue. The test vectors for Ed448 in https://tools.ietf.org/html/rfc8032#section-7.4 don't use keys that conform to any of the formats phpseclib supports so, for the unit tests, specifically, I have custom key loaders. This also serves to test custom key format support. The problem is that these unit test only key loaders were kinda treating the malformed keys added by your unit test as valid keys. To fix that I clamped down on the conditions under which these unit test only key loaders run:

terrafrost@402d932

Maybe the ability to unregister already loaded key formats might be useful idk.

Another issue: all the unit tests that use data providers (as your test does) are failing with ArgumentCountError: Too few arguments to function. I'll try to look into that this evening.

@simonLeary42
Copy link
Contributor Author

I ran into this "too few arguments" problem when I was setting up PHPUnit for the 1st time because what I read online was to use @dataProvider in a docBlock, but in newer versions that doesn't work, instead you have to use #[DataProvider("providerFuncName")]. Could that be it?

@terrafrost
Copy link
Member
terrafrost commented Apr 22, 2025 via email

@terrafrost
Copy link
Member

I've fixed the unit test issue in the 3.0 branch and have merged the cherry-picked squashed commit into master.

You were right with the attributes. phpseclib 3.0 uses what Sebastian Bergmann calls the death star version constraint whereas the master branch doesn't (the master branch uses brianiumparatest ^6.6, which in turn, uses a specific version of phpunit). I can't comment on the virtues of that vs using phpunit directly but as far as using the death star version constraint is concerned... phpseclib 3.0 would have to deal with PHPUnit's changes sooner or later, esp given how long phpseclib versions are supported. Like maybe PHPUnit 9 or 10 currently work with PHP 8.4 (for example) but will they work with PHP 9.0? idk but it's my intention that phpseclib 3.0 work with PHP 9.0 so I need to be prepared for the possibility that they won't and if I wait to fix issues when I'm trying to get the newest version of PHPUnit to run because the version I had been using doesn't work at all on it then there are going to be a lot more changes I'd have to deal with whereas if I deal with them now it's less changes I need to deal with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

uncaught TypeError when trying to load JSON string as a public key
2 participants
0