From 84437419dda482292970b16120daecfe8e712994 Mon Sep 17 00:00:00 2001 From: Fredrik82 Date: Wed, 30 Aug 2023 15:50:13 +0200 Subject: [PATCH 1/4] Removed composer.lock as it should not be present in libraries --- composer.lock | 1218 ------------------------------------------------- 1 file changed, 1218 deletions(-) delete mode 100644 composer.lock diff --git a/composer.lock b/composer.lock deleted file mode 100644 index d780af4..0000000 --- a/composer.lock +++ /dev/null @@ -1,1218 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "hash": "c5fffc50418de9a8f5af5ef506991a13", - "content-hash": "05c7e0184e3666f14bd5d80d428ecd49", - "packages": [ - { - "name": "phpseclib/phpseclib", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/41f85e9c2582b3f6d1b7d20395fb40c687ad5370", - "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phing/phing": "~2.7", - "phpunit/phpunit": "~4.0", - "sami/sami": "~2.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "suggest": { - "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", - "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", - "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", - "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." - }, - "type": "library", - "autoload": { - "files": [ - "phpseclib/bootstrap.php" - ], - "psr-4": { - "phpseclib\\": "phpseclib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jim Wigginton", - "email": "terrafrost@php.net", - "role": "Lead Developer" - }, - { - "name": "Patrick Monnerat", - "email": "pm@datasphere.ch", - "role": "Developer" - }, - { - "name": "Andreas Fischer", - "email": "bantu@phpbb.com", - "role": "Developer" - }, - { - "name": "Hans-Jürgen Petrich", - "email": "petrich@tronic-media.com", - "role": "Developer" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com", - "role": "Developer" - } - ], - "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", - "homepage": "http://phpseclib.sourceforge.net", - "keywords": [ - "BigInteger", - "aes", - "asn.1", - "asn1", - "blowfish", - "crypto", - "cryptography", - "encryption", - "rsa", - "security", - "sftp", - "signature", - "signing", - "ssh", - "twofish", - "x.509", - "x509" - ], - "time": "2016-08-18 18:49:14" - } - ], - "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", - "shasum": "" - }, - "require": { - "php": ">=5.3,<8.0-DEV" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2015-06-14 21:17:01" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "1.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "shasum": "" - }, - "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2015-12-27 11:43:31" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-06-10 09:48:41" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "0.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", - "shasum": "" - }, - "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "time": "2016-06-10 07:14:17" - }, - { - "name": "phpspec/prophecy", - "version": "v1.6.1", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-0": { - "Prophecy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2016-06-07 08:13:47" - }, - { - "name": "phpunit/php-code-coverage", - "version": "2.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" - }, - "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2015-10-06 15:47:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2015-06-21 13:08:43" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21 13:50:34" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4|~5" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2016-05-12 18:03:57" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.4.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2015-09-15 10:49:45" - }, - { - "name": "phpunit/phpunit", - "version": "4.8.27", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c062dddcb68e44b563f66ee319ddae2b5a322a90", - "reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.1", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" - }, - "suggest": { - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.8.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2016-07-21 06:48:14" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2015-10-02 06:51:40" - }, - { - "name": "sebastian/comparator", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2015-07-26 15:48:44" - }, - { - "name": "sebastian/diff", - "version": "1.4.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff" - ], - "time": "2015-12-08 07:14:41" - }, - { - "name": "sebastian/environment", - "version": "1.3.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2016-08-18 05:49:44" - }, - { - "name": "sebastian/exporter", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2016-06-17 09:04:28" - }, - { - "name": "sebastian/global-state", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2015-10-12 03:26:01" - }, - { - "name": "sebastian/recursion-context", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11 19:50:13" - }, - { - "name": "sebastian/version", - "version": "1.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "shasum": "" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21 13:59:46" - }, - { - "name": "symfony/yaml", - "version": "v3.1.3", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "1819adf2066880c7967df7180f4f662b6f0567ac" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/1819adf2066880c7967df7180f4f662b6f0567ac", - "reference": "1819adf2066880c7967df7180f4f662b6f0567ac", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2016-07-17 14:02:08" - }, - { - "name": "webmozart/assert", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", - "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", - "shasum": "" - }, - "require": { - "php": "^5.3.3|^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2016-08-09 15:02:57" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.6" - }, - "platform-dev": [] -} From b29a73c94a4f18d66f04e4c94df575d7fb807b30 Mon Sep 17 00:00:00 2001 From: Fredrik82 Date: Wed, 30 Aug 2023 15:50:49 +0200 Subject: [PATCH 2/4] Use phpseclib v3 --- src/JOSE/JWE.php | 65 +++++-- src/JOSE/JWK.php | 376 +++++++++++++++++++++++++++++++++-------- src/JOSE/JWS.php | 21 ++- test/JOSE/JWE_Test.php | 9 +- test/JOSE/JWK_Test.php | 323 ++++++++++++++++++++++++++--------- test/JOSE/JWS_Test.php | 20 +-- 6 files changed, 626 insertions(+), 188 deletions(-) diff --git a/src/JOSE/JWE.php b/src/JOSE/JWE.php index 964d8ce..9f809a4 100644 --- a/src/JOSE/JWE.php +++ b/src/JOSE/JWE.php @@ -1,8 +1,8 @@ decryptContentEncryptionKey($private_key_or_secret); $this->deriveEncryptionAndMacKeys(); $this->decryptCipherText(); - $this->checkAuthenticationTag(); + if (!in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + /* Authentication tag has already been verified in AESGCM.php for AES GCM encryption */ + $this->checkAuthenticationTag(); + } return $this; } @@ -68,11 +71,9 @@ private function rsa($public_or_private_key, $padding_mode) { } else if ($public_or_private_key instanceof RSA) { $rsa = $public_or_private_key; } else { - $rsa = new RSA(); - $rsa->loadKey($public_or_private_key); + $rsa = RSA::load($public_or_private_key); } - $rsa->setEncryptionMode($padding_mode); - return $rsa; + return $rsa->withPadding($padding_mode); } private function cipher() { @@ -147,6 +148,7 @@ private function encryptContentEncryptionKey($public_key_or_secret) { $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); break; case 'RSA-OAEP': + case 'RSA-OAEP-256': $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_OAEP); $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); break; @@ -176,6 +178,7 @@ private function decryptContentEncryptionKey($private_key_or_secret) { $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); break; case 'RSA-OAEP': + case 'RSA-OAEP-256': $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_OAEP); $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); break; @@ -227,27 +230,53 @@ private function deriveEncryptionAndMacKeysCBC($sha_size) { } private function encryptCipherText() { - $cipher = $this->cipher(); - $cipher->setKey($this->encryption_key); - $cipher->setIV($this->iv); - $this->cipher_text = $cipher->encrypt($this->plain_text); + if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + try { + list($C, $T) = AESGCM::encrypt($this->encryption_key, $this->iv, $this->plain_text, $this->compact((object) $this->header)); + $this->cipher_text = $C; + } catch (Exception $e) { + throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); + } + } else { + $cipher = $this->cipher(); + $cipher->setKey($this->encryption_key); + $cipher->setIV($this->iv); + $this->cipher_text = $cipher->encrypt($this->plain_text); + } if (!$this->cipher_text) { - throw new JOSE_Exception_DecryptionFailed('Payload encryption failed'); + throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); } } private function decryptCipherText() { - $cipher = $this->cipher(); - $cipher->setKey($this->encryption_key); - $cipher->setIV($this->iv); - $this->plain_text = $cipher->decrypt($this->cipher_text); + if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + try { + $this->plain_text = AESGCM::decrypt($this->encryption_key, $this->iv, $this->cipher_text, $this->auth_data ?: null, $this->authentication_tag); + } catch (Exception $e) { + throw new JOSE_Exception_DecryptionFailed('Payload decryption failed'); + } + } else { + $cipher = $this->cipher(); + $cipher->setKey($this->encryption_key); + $cipher->setIV($this->iv); + $this->plain_text = $cipher->decrypt($this->cipher_text); + } if (!$this->plain_text) { throw new JOSE_Exception_DecryptionFailed('Payload decryption failed'); } } private function generateAuthenticationTag() { - $this->authentication_tag = $this->calculateAuthenticationTag(); + if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + try { + list($C, $T) = AESGCM::encrypt($this->encryption_key, $this->iv, $this->plain_text, $this->compact((object) $this->header)); + $this->authentication_tag = $T; + } catch (Exception $e) { + throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); + } + } else { + $this->authentication_tag = $this->calculateAuthenticationTag(); + } } private function calculateAuthenticationTag($use_raw = false) { diff --git a/src/JOSE/JWK.php b/src/JOSE/JWK.php index 851714a..293f51c 100644 --- a/src/JOSE/JWK.php +++ b/src/JOSE/JWK.php @@ -1,90 +1,322 @@ components = $components; - if (!array_key_exists('kid', $this->components)) { - $this->components['kid'] = $this->thumbprint(); - } - } - - function toKey() { - switch ($this->components['kty']) { - case 'RSA': - $rsa = new RSA(); - $n = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['n'])), 16); - $e = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['e'])), 16); - if (array_key_exists('d', $this->components)) { - throw new JOSE_Exception_UnexpectedAlgorithm('RSA private key isn\'t supported'); - } else { - $pem_string = $rsa->_convertPublicKey($n, $e); - } - $rsa->loadKey($pem_string); - return $rsa; +use phpseclib3\Crypt\RSA; +use phpseclib3\Crypt\AES; +use phpseclib3\Crypt\Random; + +class JOSE_JWE extends JOSE_JWT { + var $plain_text; + var $cipher_text; + var $content_encryption_key; + var $jwe_encrypted_key; + var $encryption_key; + var $mac_key; + var $iv; + var $authentication_tag; + var $auth_data; + + function __construct($input = null) { + if ($input instanceof JOSE_JWT) { + $this->raw = $input->toString(); + } else { + $this->raw = $input; + } + unset($this->header['typ']); + } + + function encrypt($public_key_or_secret, $algorithm = 'RSA1_5', $encryption_method = 'A128CBC-HS256') { + $this->header['alg'] = $algorithm; + $this->header['enc'] = $encryption_method; + if ( + $public_key_or_secret instanceof JOSE_JWK && + !array_key_exists('kid', $this->header) && + array_key_exists('kid', $public_key_or_secret->components) + ) { + $this->header['kid'] = $public_key_or_secret->components['kid']; + } + $this->plain_text = $this->raw; + $this->generateContentEncryptionKey($public_key_or_secret); + $this->encryptContentEncryptionKey($public_key_or_secret); + $this->generateIv(); + $this->deriveEncryptionAndMacKeys(); + $this->encryptCipherText(); + $this->generateAuthenticationTag(); + return $this; + } + + function decrypt($private_key_or_secret) { + $this->decryptContentEncryptionKey($private_key_or_secret); + $this->deriveEncryptionAndMacKeys(); + $this->decryptCipherText(); + if (!in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + /* Authentication tag has already been verified in AESGCM.php for AES GCM encryption */ + $this->checkAuthenticationTag(); + } + return $this; + } + + function toString() { + return implode('.', array( + $this->compact((object) $this->header), + $this->compact($this->jwe_encrypted_key), + $this->compact($this->iv), + $this->compact($this->cipher_text), + $this->compact($this->authentication_tag) + )); + } + + private function rsa($public_or_private_key, $padding_mode) { + if ($public_or_private_key instanceof JOSE_JWK) { + $rsa = $public_or_private_key->toKey(); + } else if ($public_or_private_key instanceof RSA) { + $rsa = $public_or_private_key; + } else { + $rsa = RSA::load($public_or_private_key); + } + return $rsa->withPadding($padding_mode); + } + + private function cipher() { + switch ($this->header['enc']) { + case 'A128GCM': + case 'A256GCM': + throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); + case 'A128CBC-HS256': + case 'A256CBC-HS512': + $cipher = new AES(AES::MODE_CBC); + break; + default: + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + } + switch ($this->header['enc']) { + case 'A128GCM': + case 'A128CBC-HS256': + $cipher->setBlockLength(128); + break; + case 'A256GCM': + case 'A256CBC-HS512': + $cipher->setBlockLength(256); + break; default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type'); + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); } + return $cipher; } - function thumbprint($hash_algorithm = 'sha256') { - $hash = new Hash($hash_algorithm); - return JOSE_URLSafeBase64::encode( - $hash->hash( - json_encode($this->normalized()) - ) - ); + private function generateRandomBytes($length) { + return Random::string($length); } - private function normalized() { - switch ($this->components['kty']) { - case 'RSA': - return array( - 'e' => $this->components['e'], - 'kty' => $this->components['kty'], - 'n' => $this->components['n'] - ); + private function generateIv() { + switch ($this->header['enc']) { + case 'A128GCM': + case 'A128CBC-HS256': + $this->iv = $this->generateRandomBytes(128 / 8); + break; + case 'A256GCM': + case 'A256CBC-HS512': + $this->iv = $this->generateRandomBytes(256 / 8); + break; default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type'); + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); } } - function toString() { - return json_encode($this->components); - } - function __toString() { - return $this->toString(); - } - - static function encode($key, $extra_components = array()) { - switch(get_class($key)) { - case 'phpseclib\Crypt\RSA': - $components = array( - 'kty' => 'RSA', - 'e' => JOSE_URLSafeBase64::encode($key->publicExponent->toBytes()), - 'n' => JOSE_URLSafeBase64::encode($key->modulus->toBytes()) - ); - if ($key->exponent != $key->publicExponent) { - $components = array_merge($components, array( - 'd' => JOSE_URLSafeBase64::encode($key->exponent->toBytes()) - )); - } - return new self(array_merge($components, $extra_components)); + private function generateContentEncryptionKey($public_key_or_secret) { + if ($this->header['alg'] == 'dir') { + $this->content_encryption_key = $public_key_or_secret; + } else { + switch ($this->header['enc']) { + case 'A128GCM': + case 'A128CBC-HS256': + $this->content_encryption_key = $this->generateRandomBytes(256 / 8); + break; + case 'A256GCM': + case 'A256CBC-HS512': + $this->content_encryption_key = $this->generateRandomBytes(512 / 8); + break; + default: + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + } + } + } + + private function encryptContentEncryptionKey($public_key_or_secret) { + switch ($this->header['alg']) { + case 'RSA1_5': + $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_PKCS1); + $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); + break; + case 'RSA-OAEP': + case 'RSA-OAEP-256': + $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_OAEP); + $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); + break; + case 'dir': + $this->jwe_encrypted_key = ''; + return; + case 'A128KW': + case 'A256KW': + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A256KW': + throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type'); + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + } + if (!$this->jwe_encrypted_key) { + throw new JOSE_Exception_EncryptionFailed('Master key encryption failed'); } } - static function decode($components) { - $jwk = new self($components); - return $jwk->toKey(); + private function decryptContentEncryptionKey($private_key_or_secret) { + $this->generateContentEncryptionKey(null); # NOTE: run this always not to make timing difference + $fake_content_encryption_key = $this->content_encryption_key; + switch ($this->header['alg']) { + case 'RSA1_5': + $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_PKCS1); + $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); + break; + case 'RSA-OAEP': + case 'RSA-OAEP-256': + $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_OAEP); + $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); + break; + case 'dir': + $this->content_encryption_key = $private_key_or_secret; + break; + case 'A128KW': + case 'A256KW': + case 'ECDH-ES': + case 'ECDH-ES+A128KW': + case 'ECDH-ES+A256KW': + throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); + default: + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + } + if (!$this->content_encryption_key) { + # NOTE: + # Not to disclose timing difference between CEK decryption error and others. + # Mitigating Bleichenbacher Attack on PKCS#1 v1.5 + # ref.) http://inaz2.hatenablog.com/entry/2016/01/26/222303 + $this->content_encryption_key = $fake_content_encryption_key; + } + } + + private function deriveEncryptionAndMacKeys() { + switch ($this->header['enc']) { + case 'A128GCM': + case 'A256GCM': + $this->encryption_key = $this->content_encryption_key; + $this->mac_key = "won't be used"; + break; + case 'A128CBC-HS256': + $this->deriveEncryptionAndMacKeysCBC(256); + break; + case 'A256CBC-HS512': + $this->deriveEncryptionAndMacKeysCBC(512); + break; + default: + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + } + if (!$this->encryption_key || !$this->mac_key) { + throw new JOSE_Exception_DecryptionFailed('Encryption/Mac key derivation failed'); + } + } + + private function deriveEncryptionAndMacKeysCBC($sha_size) { + $this->mac_key = substr($this->content_encryption_key, 0, $sha_size / 2 / 8); + $this->encryption_key = substr($this->content_encryption_key, $sha_size / 2 / 8); + } + + private function encryptCipherText() { + if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + try { + list($C, $T) = AESGCM::encrypt($this->encryption_key, $this->iv, $this->plain_text, $this->compact((object) $this->header)); + $this->cipher_text = $C; + } catch (Exception $e) { + throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); + } + } else { + $cipher = $this->cipher(); + $cipher->setKey($this->encryption_key); + $cipher->setIV($this->iv); + $this->cipher_text = $cipher->encrypt($this->plain_text); + } + if (!$this->cipher_text) { + throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); + } + } + + private function decryptCipherText() { + if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + try { + $this->plain_text = AESGCM::decrypt($this->encryption_key, $this->iv, $this->cipher_text, $this->auth_data ?: null, $this->authentication_tag); + } catch (Exception $e) { + throw new JOSE_Exception_DecryptionFailed('Payload decryption failed'); + } + } else { + $cipher = $this->cipher(); + $cipher->setKey($this->encryption_key); + $cipher->setIV($this->iv); + $this->plain_text = $cipher->decrypt($this->cipher_text); + } + if (!$this->plain_text) { + throw new JOSE_Exception_DecryptionFailed('Payload decryption failed'); + } + } + + private function generateAuthenticationTag() { + if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { + try { + list($C, $T) = AESGCM::encrypt($this->encryption_key, $this->iv, $this->plain_text, $this->compact((object) $this->header)); + $this->authentication_tag = $T; + } catch (Exception $e) { + throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); + } + } else { + $this->authentication_tag = $this->calculateAuthenticationTag(); + } + } + + private function calculateAuthenticationTag($use_raw = false) { + switch ($this->header['enc']) { + case 'A128GCM': + case 'A256GCM': + throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); + case 'A128CBC-HS256': + return $this->calculateAuthenticationTagCBC(256); + case 'A256CBC-HS512': + return $this->calculateAuthenticationTagCBC(512); + default: + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + } + } + + private function calculateAuthenticationTagCBC($sha_size) { + if (!$this->auth_data) { + $this->auth_data = $this->compact((object) $this->header); + } + $auth_data_length = strlen($this->auth_data); + $max_32bit = 2147483647; + $secured_input = implode('', array( + $this->auth_data, + $this->iv, + $this->cipher_text, + // NOTE: PHP doesn't support 64bit big endian, so handling upper & lower 32bit. + pack('N2', ($auth_data_length / $max_32bit) * 8, ($auth_data_length % $max_32bit) * 8) + )); + return substr( + hash_hmac('sha' . $sha_size, $secured_input, $this->mac_key, true), + 0, $sha_size / 2 / 8 + ); + } + + private function checkAuthenticationTag() { + if (hash_equals($this->authentication_tag, $this->calculateAuthenticationTag())) { + return true; + } else { + throw new JOSE_Exception_UnexpectedAlgorithm('Invalid authentication tag'); + } } } \ No newline at end of file diff --git a/src/JOSE/JWS.php b/src/JOSE/JWS.php index f6c3a86..8ce2e43 100644 --- a/src/JOSE/JWS.php +++ b/src/JOSE/JWS.php @@ -1,6 +1,7 @@ loadKey($public_or_private_key); + $rsa = RSA::load($public_or_private_key); } - $rsa->setHash($this->digest()); - $rsa->setMGFHash($this->digest()); - $rsa->setSignatureMode($padding_mode); - return $rsa; + return $rsa->withHash($this->digest()) + ->withMGFHash($this->digest()) + ->withPadding($padding_mode); } private function digest() { @@ -103,7 +102,11 @@ private function _sign($private_key_or_secret) { case 'RS256': case 'RS384': case 'RS512': - return $this->rsa($private_key_or_secret, RSA::SIGNATURE_PKCS1)->sign($signature_base_string); + try { + return $this->rsa($private_key_or_secret, RSA::SIGNATURE_PKCS1)->sign($signature_base_string); + } catch (NoKeyLoadedException $ex) { + return false; + } case 'ES256': case 'ES384': case 'ES512': @@ -151,4 +154,4 @@ private function _verify($public_key_or_secret, $expected_alg = null) { throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); } } -} +} \ No newline at end of file diff --git a/test/JOSE/JWE_Test.php b/test/JOSE/JWE_Test.php index aba2756..744273a 100644 --- a/test/JOSE/JWE_Test.php +++ b/test/JOSE/JWE_Test.php @@ -1,6 +1,6 @@ assertEquals($this->plain_text, $jwe_decoded->decrypt($this->rsa_keys['private'])->plain_text); } + function testEncryptRSAOAEP256_A256CBCHS512() { + $jwe = new JOSE_JWE($this->plain_text); + $jwe->encrypt($this->rsa_keys['public'], 'RSA-OAEP-256', 'A256CBC-HS512'); + $jwe_decoded = JOSE_JWT::decode($jwe->toString()); + $this->assertEquals($this->plain_text, $jwe_decoded->decrypt($this->rsa_keys['private'])->plain_text); + } + function testEncryptDir_A128CBCHS256() { $secret = Random::string(256 / 8); $jwe = new JOSE_JWE($this->plain_text); diff --git a/test/JOSE/JWK_Test.php b/test/JOSE/JWK_Test.php index 45cc061..6025998 100644 --- a/test/JOSE/JWK_Test.php +++ b/test/JOSE/JWK_Test.php @@ -1,105 +1,276 @@ setExpectedException('JOSE_Exception_InvalidFormat'); - new JOSE_JWK(array('n' => 'n')); +class JOSE_JWS_Test extends JOSE_TestCase { + var $plain_jwt; + var $rsa_keys; + + function setUp() { + parent::setUp(); + $this->plain_jwt = new JOSE_JWT(array( + 'foo' => 'bar' + )); } - function testToString() { - $jwk = new JOSE_JWK(array('kty' => 'RSA', 'e' => 'e', 'n' => 'n')); - $this->assertEquals('{"kty":"RSA","e":"e","n":"n","kid":"lPd1Hx7fpYY23pQVKnFvOEtk_jFe5EV8ZISUGTSGA_U"}', $jwk->toString()); + function testToJSON() { + $expected = '{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9","payload":"eyJmb28iOiJiYXIifQ","signature":"GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw"}'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'RS256'); + $this->assertEquals($expected, sprintf('%s', $jws->toJSON())); } - function test__toString() { - $jwk = new JOSE_JWK(array('kty' => 'RSA', 'e' => 'e', 'n' => 'n')); - $this->assertEquals('{"kty":"RSA","e":"e","n":"n","kid":"lPd1Hx7fpYY23pQVKnFvOEtk_jFe5EV8ZISUGTSGA_U"}', sprintf('%s', $jwk)); + function testToJSONWithGeneralSyntax() { + $expected = '{"payload":"eyJmb28iOiJiYXIifQ","signatures":{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9","signature":"GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw"}}'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'RS256'); + $this->assertEquals($expected, sprintf('%s', $jws->toJSON('general-syntax'))); } - function testEncodeRSAPublicKey() { - $rsa = new RSA(); - $rsa->loadKey($this->rsa_keys['public']); - $jwk = JOSE_JWK::encode($rsa); - $this->assertInstanceOf('JOSE_JWK', $jwk); - $this->assertEquals('AQAB', $jwk->components['e']); - $this->assertEquals('x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', $jwk->components['n']); - $this->assertNotContains('d', $jwk->components); + function testSignHS256() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign('shared-secret', 'HS256'); + $this->assertEquals($expected, $jws->toString()); } - function testEncodeRSAPrivateKey() { - $rsa = new RSA(); - $rsa->loadKey($this->rsa_keys['private']); - $jwk = JOSE_JWK::encode($rsa); - $this->assertInstanceOf('JOSE_JWK', $jwk); - $this->assertEquals('AQAB', $jwk->components['e']); - $this->assertEquals('x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', $jwk->components['n']); - $this->assertEquals('S3xQjvVh-PJv9tK_gHeJB0nWBx6bewWdakI7Pm9nR30ZNKYtQc15eoESczhjsPe3z_DGJebohZmmx4bzNlQSFBzj4W1TFXFM05oqSi7DfV1jZyzlNSYKsjT0P4gBoziNwc9uDLPWNUFPo_6gF7rJo2r1chix-Oftpt2Sc0SsdyEESBMR5REMccX5gZIhN-DUTN4gt9GNeDRy9h-gNFxgNNtt17HzEg52gbl3UnEuuPXE2wcctE1nxT3WDdtVqb6nbaNfxLiaAWaL2uYBvU2_AvKu1b7VEPmP9pTEMyriVzh4Jb2ZtIUpna518M044GPKs1TgMHSAxpOaQvnpar9lrQ', $jwk->components['d']); + function testSignHS384() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJmb28iOiJiYXIifQ.EoHJwaBtAB7OQzhInUDK5QBrKqhYX8OodiAgusI3fOJsueTm6aOpKvngGj3afGQo'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign('shared-secret', 'HS384'); + $this->assertEquals($expected, $jws->toString()); } - function testEncodeWithExtraComponents() { - $rsa = new RSA(); - $rsa->loadKey($this->rsa_keys['private']); - $jwk = JOSE_JWK::encode($rsa, array( - 'kid' => '12345', - 'use' => 'sig' - )); - $this->assertEquals('12345', $jwk->components['kid']); - $this->assertEquals('sig', $jwk->components['use']); + function testSignHS512() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJmb28iOiJiYXIifQ.eLwaujbDB1c19eOGpxwMksVHCkE5XLA4eps80ZDPAE8_FdQOMQvC6lF0mtAHljAai9XHEDWMXUz1NCeovs8ZVQ'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign('shared-secret', 'HS512'); + $this->assertEquals($expected, $jws->toString()); + } + + function testSignRS256() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'RS256'); + $this->assertEquals($expected, $jws->toString()); + } + + function testSignRS384() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJmb28iOiJiYXIifQ.Odg4nlRTnH1mI1JQEJEQCB1mmqDPFn-Gf5Te8IfLzu7sGDrvZdvGe6HutsDO3mXi7FLtQcI2i0KEQxj8fDUV4vfR1fbfyGQaz02qnt3HKEOgRGwFH1l57ayGChZftXhSCpbt9sMwTg1lsZ_egThQWG0ZErkibmXIt5ZxNwITaXX4oU3k12eH492IsScz_tIaf9NCwIQlAPodiVQL7WMQgej0o4LuZKk6ZgBsDJz_Ms2_iONxzGPWOT76iLOwYT8QaEsLX6d8_WsZ4wnfaxHVlg-zNM0Lhisi_F0_tFeueDOZPJnQp_InV7iYzP4adWOItzG_Qz_-EaNGTz4RJtxqAQ'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'RS384'); + $this->assertEquals($expected, $jws->toString()); + } + + function testSignRS512() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJmb28iOiJiYXIifQ.uQAVgGt1oy8FlMaAx8UDnVwzuDuJsqYIDHm8cKRKqLqcZ0zUmQHgfonBA09r5CiqG5EGTaX58G6_hAFAmf-aRtJrm_cN-68xrliMXVH3m6vZdRKhbtYqCozjbmEH8nPwBFtlri15vhR5lWTT_x3VsZOHhuhbAFzyshIcYAxNDVkUssPWpDag26fRcPsIJ-Oozvp9ld1uOnu9BNSOCWF4DXUTRBfUx55pl1ihwgHrFt36eHdtQ90vJXflsJvLoHuKf4LKt0dOpsPYeJp74V1X06DFlVqL9JGAS3iSLZ_tK_MpZheJqIr5iPl4qWc4k6gSbeomXR1opKqWmbje5JiZmw'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'RS512'); + $this->assertEquals($expected, $jws->toString()); + } + + function testSignPS256() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJmb28iOiJiYXIifQ.x5S_So_vmBcuROQ1uqlZTCc5YWk9xMR4SyCrVwxylgewFVK-WIsiDyMvSuBeojNXk693f775HeO1h8VJIkuXN3wupPKn2OHFPvQMPdcygLxM7aGV8gG9Ocv-HHWAK_i3UQpek-2CjEDSGFBUQqvKKxqx7NrbB-xt4dBn6JeMEs5wqpADUDQWr5zC33OEwamZktPF10FS2HVRtLuS4X9J53x2kLIFxxqPq_pyvUvlfehniyzupyVMbhHPe9-kiibLVSN0dVX9w0UyNoNQ1ZxWXfMZ3gVsWIeaaXCseW8TD7Pm_7I6Y8_sALje08USJ4Sdj4ExpvJqqrnY2cCHIAGAQA'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'PS256'); + # NOTE: RSA-PSS generates different signature each time + $expected_segments = explode('.', $expected); + $given_segments = explode('.', $jws->toString()); + $this->assertEquals($expected_segments[0], $given_segments[0]); + $this->assertEquals($expected_segments[1], $given_segments[1]); + } + + function testSignPS384() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzM4NCJ9.eyJmb28iOiJiYXIifQ.vvJPhzH_aZiiFaaAPOfshgaRmiqRSmyUmvL02uZGyWNtjJuA_zEJsuvs18JzOkDgHCG5MsrfhWkJKsl9Pm2DLWo2D7b8NBKpHE1oedTptOOnk8wGWUU2vBXYmuoWcKzDrH0Bl697NTTNv72AeoMWzaOXqYTx_qcOZxlscGINm0-lqttSk-gnzqbOxSAacv_YeibofxvFNw3Q3eaP36f1glYOWHOQSSWoqe0cW0F8hxcLeEr4FPRwAaFnOfG0wDsYZ8huvEun4uopEitJugC8oYiE-iax-QbbwboIiYeZtDBG51uydkOEjKi3WexFjayiQSCgj_343mUdq1wzV9dt2w'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'PS384'); + # NOTE: RSA-PSS generates different signature each time + $expected_segments = explode('.', $expected); + $given_segments = explode('.', $jws->toString()); + $this->assertEquals($expected_segments[0], $given_segments[0]); + $this->assertEquals($expected_segments[1], $given_segments[1]); + } + + function testSignPS512() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJmb28iOiJiYXIifQ.g8x8IDQuG6-TMHowGvtFSurHrxccbP9ihmRIrwtccYxO1tkBSoU1Sgl8Cf5fj4u2E24vIQIc6feaTHIt--T2gdxvvSf2W0dhfP7GH4bajiOuL7lz2QcjypvxXdhoZM3PAGyWLYK76ZJ2RCalEvApZrWGsBud-h8Gnvd69wotm6hay8ZIbm7KEy0uuRnLF9r95uKxhMH5HVWQiPi4sw3FJgUlrBL4PeLTiRbrmVmCxuD-VTAZnxUZQkyrSwF0i4YPx9erptGQY6tndB6f_7oM8aDmj4xp3EjWIhOmJ4PfIZhBTeNpQW9eKto9Q2St_rruMlhrrFdaB7w8240pMKFkqw'; + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($this->rsa_keys['private'], 'PS512'); + # NOTE: RSA-PSS generates different signature each time + $expected_segments = explode('.', $expected); + $given_segments = explode('.', $jws->toString()); + $this->assertEquals($expected_segments[0], $given_segments[0]); + $this->assertEquals($expected_segments[1], $given_segments[1]); } - function testEncodeWithUnexpectedAlg() { - $key = new RC2(); + function testSignRS256WithInvalidPrivateKey() { + $jws = new JOSE_JWS($this->plain_jwt); + $this->setExpectedException('JOSE_Exception'); + $jws = $jws->sign('invalid pem', 'RS256'); + } + + function testSignES256() { + $jws = new JOSE_JWS($this->plain_jwt); $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - JOSE_JWK::encode($key); + $jws = $jws->sign('es key should be here', 'ES256'); } - function testDecodeRSAPublicKey() { - $components = array( - 'kty' => 'RSA', - 'e' => 'AQAB', - 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ' - ); - $key = JOSE_JWK::decode($components); - $this->assertInstanceOf('phpseclib\Crypt\RSA', $key); - $this->assertEquals( - preg_replace("/\r\n|\r|\n/", '', $this->rsa_keys['public']), - preg_replace("/\r\n|\r|\n/", '', $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1_RAW)) - ); + function testSignWithCryptRSA() { + $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; + $key = RSA::load($this->rsa_keys['private']); + $jws = new JOSE_JWS($this->plain_jwt); + $jws = $jws->sign($key, 'RS256'); + $this->assertEquals($expected, $jws->toString()); } - function testDecodeRSAPrivateKey() { - $components = array( - 'kty' => 'RSA', - 'e' => 'AQAB', - 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', - 'd' => 'S3xQjvVh-PJv9tK_gHeJB0nWBx6bewWdakI7Pm9nR30ZNKYtQc15eoESczhjsPe3z_DGJebohZmmx4bzNlQSFBzj4W1TFXFM05oqSi7DfV1jZyzlNSYKsjT0P4gBoziNwc9uDLPWNUFPo_6gF7rJo2r1chix-Oftpt2Sc0SsdyEESBMR5REMccX5gZIhN-DUTN4gt9GNeDRy9h-gNFxgNNtt17HzEg52gbl3UnEuuPXE2wcctE1nxT3WDdtVqb6nbaNfxLiaAWaL2uYBvU2_AvKu1b7VEPmP9pTEMyriVzh4Jb2ZtIUpna518M044GPKs1TgMHSAxpOaQvnpar9lrQ' - ); + function testSignWithJWK() { + $key = RSA::load($this->rsa_keys['private']); + $jwk = JOSE_JWK::encode($key); + $jws = new JOSE_JWS($this->plain_jwt); $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - JOSE_JWK::decode($components); + $jws->sign($jwk, 'RS256'); } - function testDecodeWithUnexpectedAlg() { - $components = array( - 'kty' => 'EC', - 'crv' => 'crv', - 'x' => 'x', - 'y' => 'y' - ); + function testSignUnknowAlg() { + $jws = new JOSE_JWS($this->plain_jwt); $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - JOSE_JWK::decode($components); + $jws = $jws->sign('secret', 'AES256'); + } + + function testVerifyHS256() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS256')); } - function testThumbprint() { - $rsa = new RSA(); - $rsa->loadKey($this->rsa_keys['public']); - $jwk = JOSE_JWK::encode($rsa); - $this->assertInstanceOf('JOSE_JWK', $jwk); - $this->assertEquals('nuBTimkcSt_AuEsD8Yv3l8CoGV31bu_3gsRDGN1iVKA', $jwk->thumbprint()); - $this->assertEquals('nuBTimkcSt_AuEsD8Yv3l8CoGV31bu_3gsRDGN1iVKA', $jwk->thumbprint('sha256')); - $this->assertEquals('6v7pXTnQLMiQgvJlPJUdhAUSuGLzgF8C1r3ABAMFet6bc53ea-Pq4ZGbGu3RoAFsNRT1-RhTzDqtqXuLU6NOtw', $jwk->thumbprint('sha512')); + function testVerifyHS256_without_explicit_alg() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); + $jws->verify('shared-secret'); } + function testVerifyHS384() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJmb28iOiJiYXIifQ.EoHJwaBtAB7OQzhInUDK5QBrKqhYX8OodiAgusI3fOJsueTm6aOpKvngGj3afGQo'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS384')); + } + + function testVerifyHS512() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJmb28iOiJiYXIifQ.eLwaujbDB1c19eOGpxwMksVHCkE5XLA4eps80ZDPAE8_FdQOMQvC6lF0mtAHljAai9XHEDWMXUz1NCeovs8ZVQ'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS512')); + } + + function testVerifyRS256() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); + } + + function testVerifyRS384() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJmb28iOiJiYXIifQ.Odg4nlRTnH1mI1JQEJEQCB1mmqDPFn-Gf5Te8IfLzu7sGDrvZdvGe6HutsDO3mXi7FLtQcI2i0KEQxj8fDUV4vfR1fbfyGQaz02qnt3HKEOgRGwFH1l57ayGChZftXhSCpbt9sMwTg1lsZ_egThQWG0ZErkibmXIt5ZxNwITaXX4oU3k12eH492IsScz_tIaf9NCwIQlAPodiVQL7WMQgej0o4LuZKk6ZgBsDJz_Ms2_iONxzGPWOT76iLOwYT8QaEsLX6d8_WsZ4wnfaxHVlg-zNM0Lhisi_F0_tFeueDOZPJnQp_InV7iYzP4adWOItzG_Qz_-EaNGTz4RJtxqAQ'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); + } + + function testVerifyRS512() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJmb28iOiJiYXIifQ.uQAVgGt1oy8FlMaAx8UDnVwzuDuJsqYIDHm8cKRKqLqcZ0zUmQHgfonBA09r5CiqG5EGTaX58G6_hAFAmf-aRtJrm_cN-68xrliMXVH3m6vZdRKhbtYqCozjbmEH8nPwBFtlri15vhR5lWTT_x3VsZOHhuhbAFzyshIcYAxNDVkUssPWpDag26fRcPsIJ-Oozvp9ld1uOnu9BNSOCWF4DXUTRBfUx55pl1ihwgHrFt36eHdtQ90vJXflsJvLoHuKf4LKt0dOpsPYeJp74V1X06DFlVqL9JGAS3iSLZ_tK_MpZheJqIr5iPl4qWc4k6gSbeomXR1opKqWmbje5JiZmw'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); + } + + function testVerifyPS256() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJmb28iOiJiYXIifQ.x5S_So_vmBcuROQ1uqlZTCc5YWk9xMR4SyCrVwxylgewFVK-WIsiDyMvSuBeojNXk693f775HeO1h8VJIkuXN3wupPKn2OHFPvQMPdcygLxM7aGV8gG9Ocv-HHWAK_i3UQpek-2CjEDSGFBUQqvKKxqx7NrbB-xt4dBn6JeMEs5wqpADUDQWr5zC33OEwamZktPF10FS2HVRtLuS4X9J53x2kLIFxxqPq_pyvUvlfehniyzupyVMbhHPe9-kiibLVSN0dVX9w0UyNoNQ1ZxWXfMZ3gVsWIeaaXCseW8TD7Pm_7I6Y8_sALje08USJ4Sdj4ExpvJqqrnY2cCHIAGAQA'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); + } + + function testVerifyPS384() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzM4NCJ9.eyJmb28iOiJiYXIifQ.vvJPhzH_aZiiFaaAPOfshgaRmiqRSmyUmvL02uZGyWNtjJuA_zEJsuvs18JzOkDgHCG5MsrfhWkJKsl9Pm2DLWo2D7b8NBKpHE1oedTptOOnk8wGWUU2vBXYmuoWcKzDrH0Bl697NTTNv72AeoMWzaOXqYTx_qcOZxlscGINm0-lqttSk-gnzqbOxSAacv_YeibofxvFNw3Q3eaP36f1glYOWHOQSSWoqe0cW0F8hxcLeEr4FPRwAaFnOfG0wDsYZ8huvEun4uopEitJugC8oYiE-iax-QbbwboIiYeZtDBG51uydkOEjKi3WexFjayiQSCgj_343mUdq1wzV9dt2w'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); + } + + function testVerifyPS512() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJmb28iOiJiYXIifQ.g8x8IDQuG6-TMHowGvtFSurHrxccbP9ihmRIrwtccYxO1tkBSoU1Sgl8Cf5fj4u2E24vIQIc6feaTHIt--T2gdxvvSf2W0dhfP7GH4bajiOuL7lz2QcjypvxXdhoZM3PAGyWLYK76ZJ2RCalEvApZrWGsBud-h8Gnvd69wotm6hay8ZIbm7KEy0uuRnLF9r95uKxhMH5HVWQiPi4sw3FJgUlrBL4PeLTiRbrmVmCxuD-VTAZnxUZQkyrSwF0i4YPx9erptGQY6tndB6f_7oM8aDmj4xp3EjWIhOmJ4PfIZhBTeNpQW9eKto9Q2St_rruMlhrrFdaB7w8240pMKFkqw'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); + } + + function testVerifyES256() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.MEQCIDh9M3Id8pPd9fp6kgtirYpAirRCU-H0IbaeruLOYWc_AiBhbsswHCIlY5yqWDsOU_sy3lMnyXlrYoQLcejPxL-nDg'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); + $jws = $jws->verify('es key should be here'); + } + + function testVerifyUnknowAlg() { + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJ1bmtub3duIn0.eyJmb28iOiJiYXIifQ.'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); + $jws = $jws->verify('no key works'); + } + + function testVerifyWithCryptRSA() { + $key = RSA::load($this->rsa_keys['public']); + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($key)); + } + + function testVerifyWithJWK() { + $key = RSA::load($this->rsa_keys['public']); + $jwk = JOSE_JWK::encode($key); + $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; + $jwt = JOSE_JWT::decode($input); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($jwk)); + } + + function testVerifyWithGoogleIDToken() { + $id_token_string = file_get_contents($this->fixture_dir . 'google.jwt'); + $cert_string = file_get_contents($this->fixture_dir . 'google.crt'); + $x509 = new X509(); + $x509->loadX509($cert_string); + $public_key = $x509->getPublicKey()->toString('PKCS8'); + $jwt = JOSE_JWT::decode($id_token_string); + $jws = new JOSE_JWS($jwt); + $this->assertInstanceOf('JOSE_JWS', $jws->verify($public_key)); + } + + function testVerifyMalformedJWS_HS256_to_none() { + $malformed_jwt = JOSE_JWT::decode($this->plain_jwt->toString()); + $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); + $malformed_jwt->verify('secret'); + } + + function testVerifyMalformedJWS_RS256_to_HS256_without_explicit_alg() { + $malformed_jwt = JOSE_JWT::decode( + $this->plain_jwt->sign($this->rsa_keys['public'], 'HS256')->toString() + ); + $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); + $malformed_jwt->verify($this->rsa_keys['public']); + } + + function testVerifyMalformedJWS_RS256_to_HS256_with_explicit_alg() { + $malformed_jwt = JOSE_JWT::decode( + $this->plain_jwt->sign($this->rsa_keys['public'], 'HS256')->toString() + ); + $this->setExpectedException('JOSE_Exception_VerificationFailed', 'Signature verification failed'); + $malformed_jwt->verify($this->rsa_keys['public'], 'RS256'); + } } \ No newline at end of file diff --git a/test/JOSE/JWS_Test.php b/test/JOSE/JWS_Test.php index 1e2e13d..6025998 100644 --- a/test/JOSE/JWS_Test.php +++ b/test/JOSE/JWS_Test.php @@ -1,7 +1,7 @@ loadKey($this->rsa_keys['private']); + $key = RSA::load($this->rsa_keys['private']); $jws = new JOSE_JWS($this->plain_jwt); $jws = $jws->sign($key, 'RS256'); $this->assertEquals($expected, $jws->toString()); } function testSignWithJWK() { - $key = new RSA(); - $key->loadKey($this->rsa_keys['private']); + $key = RSA::load($this->rsa_keys['private']); $jwk = JOSE_JWK::encode($key); $jws = new JOSE_JWS($this->plain_jwt); $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); @@ -227,8 +225,7 @@ function testVerifyUnknowAlg() { } function testVerifyWithCryptRSA() { - $key = new RSA(); - $key->loadKey($this->rsa_keys['public']); + $key = RSA::load($this->rsa_keys['public']); $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; $jwt = JOSE_JWT::decode($input); $jws = new JOSE_JWS($jwt); @@ -236,8 +233,7 @@ function testVerifyWithCryptRSA() { } function testVerifyWithJWK() { - $key = new RSA(); - $key->loadKey($this->rsa_keys['public']); + $key = RSA::load($this->rsa_keys['public']); $jwk = JOSE_JWK::encode($key); $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; $jwt = JOSE_JWT::decode($input); @@ -250,7 +246,7 @@ function testVerifyWithGoogleIDToken() { $cert_string = file_get_contents($this->fixture_dir . 'google.crt'); $x509 = new X509(); $x509->loadX509($cert_string); - $public_key = $x509->getPublicKey()->getPublicKey(); + $public_key = $x509->getPublicKey()->toString('PKCS8'); $jwt = JOSE_JWT::decode($id_token_string); $jws = new JOSE_JWS($jwt); $this->assertInstanceOf('JOSE_JWS', $jws->verify($public_key)); @@ -274,7 +270,7 @@ function testVerifyMalformedJWS_RS256_to_HS256_with_explicit_alg() { $malformed_jwt = JOSE_JWT::decode( $this->plain_jwt->sign($this->rsa_keys['public'], 'HS256')->toString() ); - $this->setExpectedException('PHPUnit_Framework_Error_Notice', 'Invalid signature'); + $this->setExpectedException('JOSE_Exception_VerificationFailed', 'Signature verification failed'); $malformed_jwt->verify($this->rsa_keys['public'], 'RS256'); } } \ No newline at end of file From a5093357d7d845a8af41060af758bf962a2b3bfe Mon Sep 17 00:00:00 2001 From: Fredrik82 Date: Wed, 30 Aug 2023 16:12:01 +0200 Subject: [PATCH 3/4] Fixed bad commit --- composer.json | 6 +- src/JOSE/JWE.php | 4 - src/JOSE/JWK.php | 384 ++++++++++------------------------------------- 3 files changed, 84 insertions(+), 310 deletions(-) diff --git a/composer.json b/composer.json index c6b532f..26d2c54 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "gree/jose", - "version": "2.2.1", - "description": "JWT, JWS and JWS implementation in PHP", + "version": "3.0", + "description": "JWT, JWS and JWE implementation in PHP", "keywords": [ "JSON Web Token", "JSON Web Signature", "JSON Web Encryption", "JWT", "JWS", "JWE", "JOSE", "OpenID Connect", "ID Token" @@ -18,7 +18,7 @@ ], "require": { "php": ">=5.6", - "phpseclib/phpseclib": ">=2.0.0" + "phpseclib/phpseclib": "^3.0" }, "require-dev": { "phpunit/phpunit": "4.8.*" diff --git a/src/JOSE/JWE.php b/src/JOSE/JWE.php index 9f809a4..4dd0733 100644 --- a/src/JOSE/JWE.php +++ b/src/JOSE/JWE.php @@ -48,10 +48,6 @@ function decrypt($private_key_or_secret) { $this->decryptContentEncryptionKey($private_key_or_secret); $this->deriveEncryptionAndMacKeys(); $this->decryptCipherText(); - if (!in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { - /* Authentication tag has already been verified in AESGCM.php for AES GCM encryption */ - $this->checkAuthenticationTag(); - } return $this; } diff --git a/src/JOSE/JWK.php b/src/JOSE/JWK.php index 293f51c..c6b032a 100644 --- a/src/JOSE/JWK.php +++ b/src/JOSE/JWK.php @@ -1,322 +1,100 @@ raw = $input->toString(); - } else { - $this->raw = $input; - } - unset($this->header['typ']); - } - - function encrypt($public_key_or_secret, $algorithm = 'RSA1_5', $encryption_method = 'A128CBC-HS256') { - $this->header['alg'] = $algorithm; - $this->header['enc'] = $encryption_method; - if ( - $public_key_or_secret instanceof JOSE_JWK && - !array_key_exists('kid', $this->header) && - array_key_exists('kid', $public_key_or_secret->components) - ) { - $this->header['kid'] = $public_key_or_secret->components['kid']; - } - $this->plain_text = $this->raw; - $this->generateContentEncryptionKey($public_key_or_secret); - $this->encryptContentEncryptionKey($public_key_or_secret); - $this->generateIv(); - $this->deriveEncryptionAndMacKeys(); - $this->encryptCipherText(); - $this->generateAuthenticationTag(); - return $this; - } - - function decrypt($private_key_or_secret) { - $this->decryptContentEncryptionKey($private_key_or_secret); - $this->deriveEncryptionAndMacKeys(); - $this->decryptCipherText(); - if (!in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { - /* Authentication tag has already been verified in AESGCM.php for AES GCM encryption */ - $this->checkAuthenticationTag(); - } - return $this; - } - - function toString() { - return implode('.', array( - $this->compact((object) $this->header), - $this->compact($this->jwe_encrypted_key), - $this->compact($this->iv), - $this->compact($this->cipher_text), - $this->compact($this->authentication_tag) - )); - } - - private function rsa($public_or_private_key, $padding_mode) { - if ($public_or_private_key instanceof JOSE_JWK) { - $rsa = $public_or_private_key->toKey(); - } else if ($public_or_private_key instanceof RSA) { - $rsa = $public_or_private_key; - } else { - $rsa = RSA::load($public_or_private_key); - } - return $rsa->withPadding($padding_mode); - } - - private function cipher() { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A256GCM': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - case 'A128CBC-HS256': - case 'A256CBC-HS512': - $cipher = new AES(AES::MODE_CBC); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - switch ($this->header['enc']) { - case 'A128GCM': - case 'A128CBC-HS256': - $cipher->setBlockLength(128); - break; - case 'A256GCM': - case 'A256CBC-HS512': - $cipher->setBlockLength(256); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - return $cipher; - } - - private function generateRandomBytes($length) { - return Random::string($length); - } - - private function generateIv() { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A128CBC-HS256': - $this->iv = $this->generateRandomBytes(128 / 8); - break; - case 'A256GCM': - case 'A256CBC-HS512': - $this->iv = $this->generateRandomBytes(256 / 8); - break; +use phpseclib3\Math\BigInteger; +use phpseclib3\Crypt\Hash; +use phpseclib3\Crypt\RSA\Formats\Keys\PKCS8; +use phpseclib3\Crypt\RSA\PrivateKey; +use phpseclib3\Crypt\RSA\PublicKey; + +class JOSE_JWK { + var $components = array(); + + function __construct($components = array()) { + if (!array_key_exists('kty', $components)) { + throw new JOSE_Exception_InvalidFormat('"kty" is required'); + } + $this->components = $components; + if (!array_key_exists('kid', $this->components)) { + $this->components['kid'] = $this->thumbprint(); + } + } + + function toKey() { + switch ($this->components['kty']) { + case 'RSA': + $n = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['n'])), 16); + $e = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['e'])), 16); + if (array_key_exists('d', $this->components)) { + throw new JOSE_Exception_UnexpectedAlgorithm('RSA private key isn\'t supported'); + } else { + $pem_string = PKCS8::savePublicKey($n, $e); + } + return RSA::load($pem_string); default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type'); } } - private function generateContentEncryptionKey($public_key_or_secret) { - if ($this->header['alg'] == 'dir') { - $this->content_encryption_key = $public_key_or_secret; - } else { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A128CBC-HS256': - $this->content_encryption_key = $this->generateRandomBytes(256 / 8); - break; - case 'A256GCM': - case 'A256CBC-HS512': - $this->content_encryption_key = $this->generateRandomBytes(512 / 8); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - } - } - - private function encryptContentEncryptionKey($public_key_or_secret) { - switch ($this->header['alg']) { - case 'RSA1_5': - $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_PKCS1); - $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); - break; - case 'RSA-OAEP': - case 'RSA-OAEP-256': - $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_OAEP); - $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); - break; - case 'dir': - $this->jwe_encrypted_key = ''; - return; - case 'A128KW': - case 'A256KW': - case 'ECDH-ES': - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A256KW': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - if (!$this->jwe_encrypted_key) { - throw new JOSE_Exception_EncryptionFailed('Master key encryption failed'); - } - } - - private function decryptContentEncryptionKey($private_key_or_secret) { - $this->generateContentEncryptionKey(null); # NOTE: run this always not to make timing difference - $fake_content_encryption_key = $this->content_encryption_key; - switch ($this->header['alg']) { - case 'RSA1_5': - $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_PKCS1); - $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); - break; - case 'RSA-OAEP': - case 'RSA-OAEP-256': - $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_OAEP); - $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); - break; - case 'dir': - $this->content_encryption_key = $private_key_or_secret; - break; - case 'A128KW': - case 'A256KW': - case 'ECDH-ES': - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A256KW': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - if (!$this->content_encryption_key) { - # NOTE: - # Not to disclose timing difference between CEK decryption error and others. - # Mitigating Bleichenbacher Attack on PKCS#1 v1.5 - # ref.) http://inaz2.hatenablog.com/entry/2016/01/26/222303 - $this->content_encryption_key = $fake_content_encryption_key; - } + function thumbprint($hash_algorithm = 'sha256') { + $hash = new Hash($hash_algorithm); + return JOSE_URLSafeBase64::encode( + $hash->hash( + json_encode($this->normalized()) + ) + ); } - private function deriveEncryptionAndMacKeys() { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A256GCM': - $this->encryption_key = $this->content_encryption_key; - $this->mac_key = "won't be used"; - break; - case 'A128CBC-HS256': - $this->deriveEncryptionAndMacKeysCBC(256); - break; - case 'A256CBC-HS512': - $this->deriveEncryptionAndMacKeysCBC(512); - break; + private function normalized() { + switch ($this->components['kty']) { + case 'RSA': + return array( + 'e' => $this->components['e'], + 'kty' => $this->components['kty'], + 'n' => $this->components['n'] + ); default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - if (!$this->encryption_key || !$this->mac_key) { - throw new JOSE_Exception_DecryptionFailed('Encryption/Mac key derivation failed'); - } - } - - private function deriveEncryptionAndMacKeysCBC($sha_size) { - $this->mac_key = substr($this->content_encryption_key, 0, $sha_size / 2 / 8); - $this->encryption_key = substr($this->content_encryption_key, $sha_size / 2 / 8); - } - - private function encryptCipherText() { - if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { - try { - list($C, $T) = AESGCM::encrypt($this->encryption_key, $this->iv, $this->plain_text, $this->compact((object) $this->header)); - $this->cipher_text = $C; - } catch (Exception $e) { - throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); - } - } else { - $cipher = $this->cipher(); - $cipher->setKey($this->encryption_key); - $cipher->setIV($this->iv); - $this->cipher_text = $cipher->encrypt($this->plain_text); - } - if (!$this->cipher_text) { - throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); - } - } - - private function decryptCipherText() { - if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { - try { - $this->plain_text = AESGCM::decrypt($this->encryption_key, $this->iv, $this->cipher_text, $this->auth_data ?: null, $this->authentication_tag); - } catch (Exception $e) { - throw new JOSE_Exception_DecryptionFailed('Payload decryption failed'); - } - } else { - $cipher = $this->cipher(); - $cipher->setKey($this->encryption_key); - $cipher->setIV($this->iv); - $this->plain_text = $cipher->decrypt($this->cipher_text); - } - if (!$this->plain_text) { - throw new JOSE_Exception_DecryptionFailed('Payload decryption failed'); - } - } - - private function generateAuthenticationTag() { - if (in_array($this->header['enc'], ['A128GCM', 'A256GCM'])) { - try { - list($C, $T) = AESGCM::encrypt($this->encryption_key, $this->iv, $this->plain_text, $this->compact((object) $this->header)); - $this->authentication_tag = $T; - } catch (Exception $e) { - throw new JOSE_Exception_EncryptionFailed('Payload encryption failed'); - } - } else { - $this->authentication_tag = $this->calculateAuthenticationTag(); + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type'); } } - private function calculateAuthenticationTag($use_raw = false) { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A256GCM': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - case 'A128CBC-HS256': - return $this->calculateAuthenticationTagCBC(256); - case 'A256CBC-HS512': - return $this->calculateAuthenticationTagCBC(512); + function toString() { + return json_encode($this->components); + } + function __toString() { + return $this->toString(); + } + + static function encode($key, $extra_components = array()) { + switch(true) { + case $key instanceof RSA: + switch(true) { + case $key instanceof PrivateKey: + $resource = openssl_pkey_get_private($key->toString('PKCS8')); + break; + case $key instanceof PublicKey: + $resource = openssl_pkey_get_public($key->toString('PKCS8')); + break; + } + $details = openssl_pkey_get_details($resource); + $components = array( + 'kty' => 'RSA', + 'e' => JOSE_URLSafeBase64::encode($details['rsa']['e']), + 'n' => JOSE_URLSafeBase64::encode($details['rsa']['n']) + ); + if ($key instanceof PrivateKey) { + $components = array_merge($components, array( + 'd' => JOSE_URLSafeBase64::encode($details['rsa']['d']) + )); + } + return new self(array_merge($components, $extra_components)); default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); + throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type'); } } - private function calculateAuthenticationTagCBC($sha_size) { - if (!$this->auth_data) { - $this->auth_data = $this->compact((object) $this->header); - } - $auth_data_length = strlen($this->auth_data); - $max_32bit = 2147483647; - $secured_input = implode('', array( - $this->auth_data, - $this->iv, - $this->cipher_text, - // NOTE: PHP doesn't support 64bit big endian, so handling upper & lower 32bit. - pack('N2', ($auth_data_length / $max_32bit) * 8, ($auth_data_length % $max_32bit) * 8) - )); - return substr( - hash_hmac('sha' . $sha_size, $secured_input, $this->mac_key, true), - 0, $sha_size / 2 / 8 - ); - } - - private function checkAuthenticationTag() { - if (hash_equals($this->authentication_tag, $this->calculateAuthenticationTag())) { - return true; - } else { - throw new JOSE_Exception_UnexpectedAlgorithm('Invalid authentication tag'); - } + static function decode($components) { + $jwk = new self($components); + return $jwk->toKey(); } } \ No newline at end of file From ce4f29d52593dc4970bf7c35759bbc4734c38b3d Mon Sep 17 00:00:00 2001 From: Fredrik82 Date: Wed, 30 Aug 2023 16:22:01 +0200 Subject: [PATCH 4/4] Restored bad commits --- src/JOSE/JWE.php | 1 + test/JOSE/JWK_Test.php | 317 +++++++++-------------------------------- 2 files changed, 72 insertions(+), 246 deletions(-) diff --git a/src/JOSE/JWE.php b/src/JOSE/JWE.php index 4dd0733..46fdacc 100644 --- a/src/JOSE/JWE.php +++ b/src/JOSE/JWE.php @@ -48,6 +48,7 @@ function decrypt($private_key_or_secret) { $this->decryptContentEncryptionKey($private_key_or_secret); $this->deriveEncryptionAndMacKeys(); $this->decryptCipherText(); + $this->checkAuthenticationTag(); return $this; } diff --git a/test/JOSE/JWK_Test.php b/test/JOSE/JWK_Test.php index 6025998..be35a9d 100644 --- a/test/JOSE/JWK_Test.php +++ b/test/JOSE/JWK_Test.php @@ -1,276 +1,101 @@ plain_jwt = new JOSE_JWT(array( - 'foo' => 'bar' - )); - } - - function testToJSON() { - $expected = '{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9","payload":"eyJmb28iOiJiYXIifQ","signature":"GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw"}'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'RS256'); - $this->assertEquals($expected, sprintf('%s', $jws->toJSON())); - } - - function testToJSONWithGeneralSyntax() { - $expected = '{"payload":"eyJmb28iOiJiYXIifQ","signatures":{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9","signature":"GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw"}}'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'RS256'); - $this->assertEquals($expected, sprintf('%s', $jws->toJSON('general-syntax'))); - } - - function testSignHS256() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign('shared-secret', 'HS256'); - $this->assertEquals($expected, $jws->toString()); - } - - function testSignHS384() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJmb28iOiJiYXIifQ.EoHJwaBtAB7OQzhInUDK5QBrKqhYX8OodiAgusI3fOJsueTm6aOpKvngGj3afGQo'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign('shared-secret', 'HS384'); - $this->assertEquals($expected, $jws->toString()); - } - - function testSignHS512() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJmb28iOiJiYXIifQ.eLwaujbDB1c19eOGpxwMksVHCkE5XLA4eps80ZDPAE8_FdQOMQvC6lF0mtAHljAai9XHEDWMXUz1NCeovs8ZVQ'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign('shared-secret', 'HS512'); - $this->assertEquals($expected, $jws->toString()); - } - - function testSignRS256() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'RS256'); - $this->assertEquals($expected, $jws->toString()); - } - - function testSignRS384() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJmb28iOiJiYXIifQ.Odg4nlRTnH1mI1JQEJEQCB1mmqDPFn-Gf5Te8IfLzu7sGDrvZdvGe6HutsDO3mXi7FLtQcI2i0KEQxj8fDUV4vfR1fbfyGQaz02qnt3HKEOgRGwFH1l57ayGChZftXhSCpbt9sMwTg1lsZ_egThQWG0ZErkibmXIt5ZxNwITaXX4oU3k12eH492IsScz_tIaf9NCwIQlAPodiVQL7WMQgej0o4LuZKk6ZgBsDJz_Ms2_iONxzGPWOT76iLOwYT8QaEsLX6d8_WsZ4wnfaxHVlg-zNM0Lhisi_F0_tFeueDOZPJnQp_InV7iYzP4adWOItzG_Qz_-EaNGTz4RJtxqAQ'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'RS384'); - $this->assertEquals($expected, $jws->toString()); +class JOSE_JWK_Test extends JOSE_TestCase { + function testConstructWithoutKTY() { + $this->setExpectedException('JOSE_Exception_InvalidFormat'); + new JOSE_JWK(array('n' => 'n')); } - function testSignRS512() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJmb28iOiJiYXIifQ.uQAVgGt1oy8FlMaAx8UDnVwzuDuJsqYIDHm8cKRKqLqcZ0zUmQHgfonBA09r5CiqG5EGTaX58G6_hAFAmf-aRtJrm_cN-68xrliMXVH3m6vZdRKhbtYqCozjbmEH8nPwBFtlri15vhR5lWTT_x3VsZOHhuhbAFzyshIcYAxNDVkUssPWpDag26fRcPsIJ-Oozvp9ld1uOnu9BNSOCWF4DXUTRBfUx55pl1ihwgHrFt36eHdtQ90vJXflsJvLoHuKf4LKt0dOpsPYeJp74V1X06DFlVqL9JGAS3iSLZ_tK_MpZheJqIr5iPl4qWc4k6gSbeomXR1opKqWmbje5JiZmw'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'RS512'); - $this->assertEquals($expected, $jws->toString()); + function testToString() { + $jwk = new JOSE_JWK(array('kty' => 'RSA', 'e' => 'e', 'n' => 'n')); + $this->assertEquals('{"kty":"RSA","e":"e","n":"n","kid":"lPd1Hx7fpYY23pQVKnFvOEtk_jFe5EV8ZISUGTSGA_U"}', $jwk->toString()); } - function testSignPS256() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJmb28iOiJiYXIifQ.x5S_So_vmBcuROQ1uqlZTCc5YWk9xMR4SyCrVwxylgewFVK-WIsiDyMvSuBeojNXk693f775HeO1h8VJIkuXN3wupPKn2OHFPvQMPdcygLxM7aGV8gG9Ocv-HHWAK_i3UQpek-2CjEDSGFBUQqvKKxqx7NrbB-xt4dBn6JeMEs5wqpADUDQWr5zC33OEwamZktPF10FS2HVRtLuS4X9J53x2kLIFxxqPq_pyvUvlfehniyzupyVMbhHPe9-kiibLVSN0dVX9w0UyNoNQ1ZxWXfMZ3gVsWIeaaXCseW8TD7Pm_7I6Y8_sALje08USJ4Sdj4ExpvJqqrnY2cCHIAGAQA'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'PS256'); - # NOTE: RSA-PSS generates different signature each time - $expected_segments = explode('.', $expected); - $given_segments = explode('.', $jws->toString()); - $this->assertEquals($expected_segments[0], $given_segments[0]); - $this->assertEquals($expected_segments[1], $given_segments[1]); + function test__toString() { + $jwk = new JOSE_JWK(array('kty' => 'RSA', 'e' => 'e', 'n' => 'n')); + $this->assertEquals('{"kty":"RSA","e":"e","n":"n","kid":"lPd1Hx7fpYY23pQVKnFvOEtk_jFe5EV8ZISUGTSGA_U"}', sprintf('%s', $jwk)); } - function testSignPS384() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzM4NCJ9.eyJmb28iOiJiYXIifQ.vvJPhzH_aZiiFaaAPOfshgaRmiqRSmyUmvL02uZGyWNtjJuA_zEJsuvs18JzOkDgHCG5MsrfhWkJKsl9Pm2DLWo2D7b8NBKpHE1oedTptOOnk8wGWUU2vBXYmuoWcKzDrH0Bl697NTTNv72AeoMWzaOXqYTx_qcOZxlscGINm0-lqttSk-gnzqbOxSAacv_YeibofxvFNw3Q3eaP36f1glYOWHOQSSWoqe0cW0F8hxcLeEr4FPRwAaFnOfG0wDsYZ8huvEun4uopEitJugC8oYiE-iax-QbbwboIiYeZtDBG51uydkOEjKi3WexFjayiQSCgj_343mUdq1wzV9dt2w'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'PS384'); - # NOTE: RSA-PSS generates different signature each time - $expected_segments = explode('.', $expected); - $given_segments = explode('.', $jws->toString()); - $this->assertEquals($expected_segments[0], $given_segments[0]); - $this->assertEquals($expected_segments[1], $given_segments[1]); - } - - function testSignPS512() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJmb28iOiJiYXIifQ.g8x8IDQuG6-TMHowGvtFSurHrxccbP9ihmRIrwtccYxO1tkBSoU1Sgl8Cf5fj4u2E24vIQIc6feaTHIt--T2gdxvvSf2W0dhfP7GH4bajiOuL7lz2QcjypvxXdhoZM3PAGyWLYK76ZJ2RCalEvApZrWGsBud-h8Gnvd69wotm6hay8ZIbm7KEy0uuRnLF9r95uKxhMH5HVWQiPi4sw3FJgUlrBL4PeLTiRbrmVmCxuD-VTAZnxUZQkyrSwF0i4YPx9erptGQY6tndB6f_7oM8aDmj4xp3EjWIhOmJ4PfIZhBTeNpQW9eKto9Q2St_rruMlhrrFdaB7w8240pMKFkqw'; - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($this->rsa_keys['private'], 'PS512'); - # NOTE: RSA-PSS generates different signature each time - $expected_segments = explode('.', $expected); - $given_segments = explode('.', $jws->toString()); - $this->assertEquals($expected_segments[0], $given_segments[0]); - $this->assertEquals($expected_segments[1], $given_segments[1]); - } - - function testSignRS256WithInvalidPrivateKey() { - $jws = new JOSE_JWS($this->plain_jwt); - $this->setExpectedException('JOSE_Exception'); - $jws = $jws->sign('invalid pem', 'RS256'); - } - - function testSignES256() { - $jws = new JOSE_JWS($this->plain_jwt); - $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $jws = $jws->sign('es key should be here', 'ES256'); - } - - function testSignWithCryptRSA() { - $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; - $key = RSA::load($this->rsa_keys['private']); - $jws = new JOSE_JWS($this->plain_jwt); - $jws = $jws->sign($key, 'RS256'); - $this->assertEquals($expected, $jws->toString()); - } - - function testSignWithJWK() { - $key = RSA::load($this->rsa_keys['private']); - $jwk = JOSE_JWK::encode($key); - $jws = new JOSE_JWS($this->plain_jwt); - $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $jws->sign($jwk, 'RS256'); - } - - function testSignUnknowAlg() { - $jws = new JOSE_JWS($this->plain_jwt); - $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $jws = $jws->sign('secret', 'AES256'); + function testEncodeRSAPublicKey() { + $rsa = RSA::load($this->rsa_keys['public']); + $jwk = JOSE_JWK::encode($rsa); + $this->assertInstanceOf('JOSE_JWK', $jwk); + $this->assertEquals('AQAB', $jwk->components['e']); + $this->assertEquals('x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', $jwk->components['n']); + $this->assertNotContains('d', $jwk->components); } - function testVerifyHS256() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS256')); + function testEncodeRSAPrivateKey() { + $rsa = RSA::load($this->rsa_keys['private']); + $jwk = JOSE_JWK::encode($rsa); + $this->assertInstanceOf('JOSE_JWK', $jwk); + $this->assertEquals('AQAB', $jwk->components['e']); + $this->assertEquals('x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', $jwk->components['n']); + $this->assertEquals('S3xQjvVh-PJv9tK_gHeJB0nWBx6bewWdakI7Pm9nR30ZNKYtQc15eoESczhjsPe3z_DGJebohZmmx4bzNlQSFBzj4W1TFXFM05oqSi7DfV1jZyzlNSYKsjT0P4gBoziNwc9uDLPWNUFPo_6gF7rJo2r1chix-Oftpt2Sc0SsdyEESBMR5REMccX5gZIhN-DUTN4gt9GNeDRy9h-gNFxgNNtt17HzEg52gbl3UnEuuPXE2wcctE1nxT3WDdtVqb6nbaNfxLiaAWaL2uYBvU2_AvKu1b7VEPmP9pTEMyriVzh4Jb2ZtIUpna518M044GPKs1TgMHSAxpOaQvnpar9lrQ', $jwk->components['d']); } - function testVerifyHS256_without_explicit_alg() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $jws->verify('shared-secret'); - } - - function testVerifyHS384() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJmb28iOiJiYXIifQ.EoHJwaBtAB7OQzhInUDK5QBrKqhYX8OodiAgusI3fOJsueTm6aOpKvngGj3afGQo'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS384')); - } - - function testVerifyHS512() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJmb28iOiJiYXIifQ.eLwaujbDB1c19eOGpxwMksVHCkE5XLA4eps80ZDPAE8_FdQOMQvC6lF0mtAHljAai9XHEDWMXUz1NCeovs8ZVQ'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS512')); - } - - function testVerifyRS256() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); - } - - function testVerifyRS384() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJmb28iOiJiYXIifQ.Odg4nlRTnH1mI1JQEJEQCB1mmqDPFn-Gf5Te8IfLzu7sGDrvZdvGe6HutsDO3mXi7FLtQcI2i0KEQxj8fDUV4vfR1fbfyGQaz02qnt3HKEOgRGwFH1l57ayGChZftXhSCpbt9sMwTg1lsZ_egThQWG0ZErkibmXIt5ZxNwITaXX4oU3k12eH492IsScz_tIaf9NCwIQlAPodiVQL7WMQgej0o4LuZKk6ZgBsDJz_Ms2_iONxzGPWOT76iLOwYT8QaEsLX6d8_WsZ4wnfaxHVlg-zNM0Lhisi_F0_tFeueDOZPJnQp_InV7iYzP4adWOItzG_Qz_-EaNGTz4RJtxqAQ'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); - } - - function testVerifyRS512() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJmb28iOiJiYXIifQ.uQAVgGt1oy8FlMaAx8UDnVwzuDuJsqYIDHm8cKRKqLqcZ0zUmQHgfonBA09r5CiqG5EGTaX58G6_hAFAmf-aRtJrm_cN-68xrliMXVH3m6vZdRKhbtYqCozjbmEH8nPwBFtlri15vhR5lWTT_x3VsZOHhuhbAFzyshIcYAxNDVkUssPWpDag26fRcPsIJ-Oozvp9ld1uOnu9BNSOCWF4DXUTRBfUx55pl1ihwgHrFt36eHdtQ90vJXflsJvLoHuKf4LKt0dOpsPYeJp74V1X06DFlVqL9JGAS3iSLZ_tK_MpZheJqIr5iPl4qWc4k6gSbeomXR1opKqWmbje5JiZmw'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); - } - - function testVerifyPS256() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJmb28iOiJiYXIifQ.x5S_So_vmBcuROQ1uqlZTCc5YWk9xMR4SyCrVwxylgewFVK-WIsiDyMvSuBeojNXk693f775HeO1h8VJIkuXN3wupPKn2OHFPvQMPdcygLxM7aGV8gG9Ocv-HHWAK_i3UQpek-2CjEDSGFBUQqvKKxqx7NrbB-xt4dBn6JeMEs5wqpADUDQWr5zC33OEwamZktPF10FS2HVRtLuS4X9J53x2kLIFxxqPq_pyvUvlfehniyzupyVMbhHPe9-kiibLVSN0dVX9w0UyNoNQ1ZxWXfMZ3gVsWIeaaXCseW8TD7Pm_7I6Y8_sALje08USJ4Sdj4ExpvJqqrnY2cCHIAGAQA'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); - } - - function testVerifyPS384() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzM4NCJ9.eyJmb28iOiJiYXIifQ.vvJPhzH_aZiiFaaAPOfshgaRmiqRSmyUmvL02uZGyWNtjJuA_zEJsuvs18JzOkDgHCG5MsrfhWkJKsl9Pm2DLWo2D7b8NBKpHE1oedTptOOnk8wGWUU2vBXYmuoWcKzDrH0Bl697NTTNv72AeoMWzaOXqYTx_qcOZxlscGINm0-lqttSk-gnzqbOxSAacv_YeibofxvFNw3Q3eaP36f1glYOWHOQSSWoqe0cW0F8hxcLeEr4FPRwAaFnOfG0wDsYZ8huvEun4uopEitJugC8oYiE-iax-QbbwboIiYeZtDBG51uydkOEjKi3WexFjayiQSCgj_343mUdq1wzV9dt2w'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); - } - - function testVerifyPS512() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJmb28iOiJiYXIifQ.g8x8IDQuG6-TMHowGvtFSurHrxccbP9ihmRIrwtccYxO1tkBSoU1Sgl8Cf5fj4u2E24vIQIc6feaTHIt--T2gdxvvSf2W0dhfP7GH4bajiOuL7lz2QcjypvxXdhoZM3PAGyWLYK76ZJ2RCalEvApZrWGsBud-h8Gnvd69wotm6hay8ZIbm7KEy0uuRnLF9r95uKxhMH5HVWQiPi4sw3FJgUlrBL4PeLTiRbrmVmCxuD-VTAZnxUZQkyrSwF0i4YPx9erptGQY6tndB6f_7oM8aDmj4xp3EjWIhOmJ4PfIZhBTeNpQW9eKto9Q2St_rruMlhrrFdaB7w8240pMKFkqw'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public'])); - } - - function testVerifyES256() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.MEQCIDh9M3Id8pPd9fp6kgtirYpAirRCU-H0IbaeruLOYWc_AiBhbsswHCIlY5yqWDsOU_sy3lMnyXlrYoQLcejPxL-nDg'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $jws = $jws->verify('es key should be here'); + function testEncodeWithExtraComponents() { + $rsa = RSA::load($this->rsa_keys['private']); + $jwk = JOSE_JWK::encode($rsa, array( + 'kid' => '12345', + 'use' => 'sig' + )); + $this->assertEquals('12345', $jwk->components['kid']); + $this->assertEquals('sig', $jwk->components['use']); } - function testVerifyUnknowAlg() { - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJ1bmtub3duIn0.eyJmb28iOiJiYXIifQ.'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); + function testEncodeWithUnexpectedAlg() { + $key = new RC2('CBC'); $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $jws = $jws->verify('no key works'); - } - - function testVerifyWithCryptRSA() { - $key = RSA::load($this->rsa_keys['public']); - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($key)); + JOSE_JWK::encode($key); } - function testVerifyWithJWK() { - $key = RSA::load($this->rsa_keys['public']); - $jwk = JOSE_JWK::encode($key); - $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw'; - $jwt = JOSE_JWT::decode($input); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($jwk)); - } - - function testVerifyWithGoogleIDToken() { - $id_token_string = file_get_contents($this->fixture_dir . 'google.jwt'); - $cert_string = file_get_contents($this->fixture_dir . 'google.crt'); - $x509 = new X509(); - $x509->loadX509($cert_string); - $public_key = $x509->getPublicKey()->toString('PKCS8'); - $jwt = JOSE_JWT::decode($id_token_string); - $jws = new JOSE_JWS($jwt); - $this->assertInstanceOf('JOSE_JWS', $jws->verify($public_key)); + function testDecodeRSAPublicKey() { + $components = array( + 'kty' => 'RSA', + 'e' => 'AQAB', + 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ' + ); + $key = JOSE_JWK::decode($components); + $this->assertInstanceOf('phpseclib3\Crypt\RSA', $key); + $this->assertEquals( + preg_replace("/\r\n|\r|\n/", '', $this->rsa_keys['public']), + preg_replace("/\r\n|\r|\n/", '', $key->toString('PKCS1')) + ); } - function testVerifyMalformedJWS_HS256_to_none() { - $malformed_jwt = JOSE_JWT::decode($this->plain_jwt->toString()); + function testDecodeRSAPrivateKey() { + $components = array( + 'kty' => 'RSA', + 'e' => 'AQAB', + 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', + 'd' => 'S3xQjvVh-PJv9tK_gHeJB0nWBx6bewWdakI7Pm9nR30ZNKYtQc15eoESczhjsPe3z_DGJebohZmmx4bzNlQSFBzj4W1TFXFM05oqSi7DfV1jZyzlNSYKsjT0P4gBoziNwc9uDLPWNUFPo_6gF7rJo2r1chix-Oftpt2Sc0SsdyEESBMR5REMccX5gZIhN-DUTN4gt9GNeDRy9h-gNFxgNNtt17HzEg52gbl3UnEuuPXE2wcctE1nxT3WDdtVqb6nbaNfxLiaAWaL2uYBvU2_AvKu1b7VEPmP9pTEMyriVzh4Jb2ZtIUpna518M044GPKs1TgMHSAxpOaQvnpar9lrQ' + ); $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $malformed_jwt->verify('secret'); + JOSE_JWK::decode($components); } - function testVerifyMalformedJWS_RS256_to_HS256_without_explicit_alg() { - $malformed_jwt = JOSE_JWT::decode( - $this->plain_jwt->sign($this->rsa_keys['public'], 'HS256')->toString() + function testDecodeWithUnexpectedAlg() { + $components = array( + 'kty' => 'EC', + 'crv' => 'crv', + 'x' => 'x', + 'y' => 'y' ); $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm'); - $malformed_jwt->verify($this->rsa_keys['public']); + JOSE_JWK::decode($components); } - function testVerifyMalformedJWS_RS256_to_HS256_with_explicit_alg() { - $malformed_jwt = JOSE_JWT::decode( - $this->plain_jwt->sign($this->rsa_keys['public'], 'HS256')->toString() - ); - $this->setExpectedException('JOSE_Exception_VerificationFailed', 'Signature verification failed'); - $malformed_jwt->verify($this->rsa_keys['public'], 'RS256'); + function testThumbprint() { + $rsa = RSA::load($this->rsa_keys['public']); + $jwk = JOSE_JWK::encode($rsa); + $this->assertInstanceOf('JOSE_JWK', $jwk); + $this->assertEquals('nuBTimkcSt_AuEsD8Yv3l8CoGV31bu_3gsRDGN1iVKA', $jwk->thumbprint()); + $this->assertEquals('nuBTimkcSt_AuEsD8Yv3l8CoGV31bu_3gsRDGN1iVKA', $jwk->thumbprint('sha256')); + $this->assertEquals('6v7pXTnQLMiQgvJlPJUdhAUSuGLzgF8C1r3ABAMFet6bc53ea-Pq4ZGbGu3RoAFsNRT1-RhTzDqtqXuLU6NOtw', $jwk->thumbprint('sha512')); } + } \ No newline at end of file