├── .github
└── FUNDING.yml
├── .gitignore
├── .travis.yml
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── Rakefile
├── composer.json
├── composer.lock
├── example
└── IdToken.php
├── src
└── JOSE
│ ├── Exception.php
│ ├── Exception
│ ├── DecryptionFailed.php
│ ├── EncryptionFailed.php
│ ├── InvalidFormat.php
│ ├── UnexpectedAlgorithm.php
│ └── VerificationFailed.php
│ ├── JWE.php
│ ├── JWK.php
│ ├── JWKSet.php
│ ├── JWS.php
│ ├── JWT.php
│ └── URLSafeBase64.php
└── test
├── JOSE
├── JWE_Test.php
├── JWKSet_Test.php
├── JWK_Test.php
├── JWS_Test.php
├── JWT_Test.php
└── TestCase.php
├── bootstrap.php
├── fixtures
├── google.crt
├── google.jwt
├── private_key.pem
└── public_key.pem
└── phpunit.xml
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: nov
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | result.xml
3 | composer.phar
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.6
5 | - 7.0
6 |
7 | before_script:
8 | - composer install --dev
9 |
10 | script: ./vendor/bin/phpunit -c test/phpunit.xml
11 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | gem 'rake'
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | specs:
3 | rake (10.4.2)
4 |
5 | PLATFORMS
6 | ruby
7 |
8 | DEPENDENCIES
9 | rake
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | http://www.opensource.org/licenses/mit-license.php
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2013 Nov Matake & GREE Inc.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7 |
8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 |
10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JOSE
2 |
3 | PHP JOSE (Javascript Object Signing and Encryption) Implementation
4 |
5 | [](https://travis-ci.org/nov/jose-php)
6 |
7 | ## Requirements
8 |
9 | phpseclib is required.
10 | http://phpseclib.sourceforge.net
11 |
12 | ## Example
13 |
14 | ### JWT
15 |
16 | #### Encoding
17 |
18 | ```php
19 | $jwt = new JOSE_JWT(array(
20 | 'foo' => 'bar'
21 | ));
22 | $jwt->toString();
23 | ```
24 |
25 | #### Decoding
26 |
27 | ```php
28 | $jwt_string = 'eyJ...';
29 | $jwt = JOSE_JWT::decode($jwt_string);
30 | ```
31 |
32 | ### JWS
33 |
34 | #### Signing
35 |
36 | ```php
37 | $private_key = "-----BEGIN RSA PRIVATE KEY-----\n....";
38 | $jwt = new JOSE_JWT(array(
39 | 'foo' => 'bar'
40 | ));
41 | $jws = $jwt->sign($private_key, 'RS256');
42 | ```
43 |
44 | NOTE: `$private_key` can be `phpseclib\Crypt\RSA` instance.
45 |
46 | #### Verification
47 |
48 | ```php
49 | $public_key = "-----BEGIN RSA PUBLIC KEY-----\n....";
50 | $jwt_string = 'eyJ...';
51 | $jws = JOSE_JWT::decode($jwt_string);
52 | $jws->verify($public_key, 'RS256');
53 | ```
54 |
55 | NOTE: `$public_key` can be `JOSE_JWK` or `phpseclib\Crypt\RSA` instance.
56 |
57 | ### JWE
58 |
59 | #### Encryption
60 |
61 | ```php
62 | $jwe = new JOSE_JWE($plain_text);
63 | $jwe->encrypt(file_get_contents('/path/to/public_key.pem'));
64 | $jwe->toString();
65 | ```
66 |
67 | #### Decryption
68 |
69 | ```php
70 | $jwt_string = 'eyJ...';
71 | $jwe = JOSE_JWT::decode($jwt_string);
72 | $jwe->decrypt($private_key);
73 | ```
74 |
75 | ### JWK
76 |
77 | #### Encode
78 |
79 | ##### RSA Public Key
80 |
81 | ```php
82 | $public_key = new phpseclib\Crypt\RSA();
83 | $public_key->loadKey('-----BEGIN RSA PUBLIC KEY-----\n...');
84 | JOSE_JWK::encode($public_key); # => JOSE_JWK instance
85 | ```
86 |
87 | ##### RSA Private Key
88 |
89 | ```php
90 | $private_key = new phpseclib\Crypt\RSA();
91 | $private_key->setPassword($pass_phrase); # skip if not encrypted
92 | $private_key->loadKey('-----BEGIN RSA PRIVATE KEY-----\n...');
93 | JOSE_JWK::encode($private_key); # => JOSE_JWK instance
94 | ```
95 |
96 | #### Decode
97 |
98 | ##### RSA Public Key
99 |
100 | ```php
101 | # public key
102 | $components = array(
103 | 'kty' => 'RSA',
104 | 'e' => 'AQAB',
105 | 'n' => 'x9vNhcvSrxjsegZAAo4OEuo...'
106 | );
107 | JOSE_JWK::decode($components); # => phpseclib\Crypt\RSA instance
108 | ```
109 |
110 | ##### RSA Private Key
111 |
112 | Not supported.
113 |
114 | ## Run Test
115 |
116 | ```bash
117 | git clone git://github.com/nov/jose-php.git
118 | cd jose
119 | php composer.phar install --dev
120 | ./vendor/bin/phpunit -c test/phpunit.xml --tap
121 | ```
122 |
123 | ## Copyright
124 |
125 | Copyright © 2013 Nov Matake & GREE Inc. See LICENSE for details.
126 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | def exec(command, stdout_required = false)
2 | if stdout_required
3 | `#{command}`
4 | else
5 | system command
6 | end
7 | end
8 |
9 | desc 'run test'
10 | task :spec do
11 | exec 'php composer.phar install --dev'
12 | exec './vendor/bin/phpunit -c test/phpunit.xml --coverage-html coverage'
13 | exec 'open coverage/index.html'
14 | end
15 |
16 | desc 'release new version'
17 | task :release do
18 | require 'json'
19 | version = JSON.parse(File.read('composer.json'))['version']
20 | tags = exec('git tag', :stdout_required).split
21 | if tags.include?(version)
22 | puts "v.#{version} is already released."
23 | else
24 | puts "releasing v#{version} .."
25 | exec "git tag -a #{version}"
26 | exec "git push origin #{version}"
27 | end
28 | end
29 |
30 | task default: :spec
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gree/jose",
3 | "version": "2.2.1",
4 | "description": "JWT, JWS and JWS implementation in PHP",
5 | "keywords": [
6 | "JSON Web Token", "JSON Web Signature", "JSON Web Encryption",
7 | "JWT", "JWS", "JWE", "JOSE", "OpenID Connect", "ID Token"
8 | ],
9 | "homepage": "https://github.com/nov/jose",
10 | "license": "MIT",
11 | "type": "library",
12 | "authors": [
13 | {
14 | "name": "Nov Matake",
15 | "email": "nov@matake.jp",
16 | "homepage": "http://matake.jp"
17 | }
18 | ],
19 | "require": {
20 | "php": ">=5.6",
21 | "phpseclib/phpseclib": ">=2.0.0"
22 | },
23 | "require-dev": {
24 | "phpunit/phpunit": "4.8.*"
25 | },
26 | "include-path": ["src/"],
27 | "autoload": {
28 | "psr-0": {
29 | "JOSE": "src/"
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "c5fffc50418de9a8f5af5ef506991a13",
8 | "content-hash": "05c7e0184e3666f14bd5d80d428ecd49",
9 | "packages": [
10 | {
11 | "name": "phpseclib/phpseclib",
12 | "version": "2.0.3",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/phpseclib/phpseclib.git",
16 | "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/41f85e9c2582b3f6d1b7d20395fb40c687ad5370",
21 | "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": ">=5.3.3"
26 | },
27 | "require-dev": {
28 | "phing/phing": "~2.7",
29 | "phpunit/phpunit": "~4.0",
30 | "sami/sami": "~2.0",
31 | "squizlabs/php_codesniffer": "~2.0"
32 | },
33 | "suggest": {
34 | "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
35 | "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
36 | "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
37 | "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
38 | },
39 | "type": "library",
40 | "autoload": {
41 | "files": [
42 | "phpseclib/bootstrap.php"
43 | ],
44 | "psr-4": {
45 | "phpseclib\\": "phpseclib/"
46 | }
47 | },
48 | "notification-url": "https://packagist.org/downloads/",
49 | "license": [
50 | "MIT"
51 | ],
52 | "authors": [
53 | {
54 | "name": "Jim Wigginton",
55 | "email": "terrafrost@php.net",
56 | "role": "Lead Developer"
57 | },
58 | {
59 | "name": "Patrick Monnerat",
60 | "email": "pm@datasphere.ch",
61 | "role": "Developer"
62 | },
63 | {
64 | "name": "Andreas Fischer",
65 | "email": "bantu@phpbb.com",
66 | "role": "Developer"
67 | },
68 | {
69 | "name": "Hans-Jürgen Petrich",
70 | "email": "petrich@tronic-media.com",
71 | "role": "Developer"
72 | },
73 | {
74 | "name": "Graham Campbell",
75 | "email": "graham@alt-three.com",
76 | "role": "Developer"
77 | }
78 | ],
79 | "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
80 | "homepage": "http://phpseclib.sourceforge.net",
81 | "keywords": [
82 | "BigInteger",
83 | "aes",
84 | "asn.1",
85 | "asn1",
86 | "blowfish",
87 | "crypto",
88 | "cryptography",
89 | "encryption",
90 | "rsa",
91 | "security",
92 | "sftp",
93 | "signature",
94 | "signing",
95 | "ssh",
96 | "twofish",
97 | "x.509",
98 | "x509"
99 | ],
100 | "time": "2016-08-18 18:49:14"
101 | }
102 | ],
103 | "packages-dev": [
104 | {
105 | "name": "doctrine/instantiator",
106 | "version": "1.0.5",
107 | "source": {
108 | "type": "git",
109 | "url": "https://github.com/doctrine/instantiator.git",
110 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
111 | },
112 | "dist": {
113 | "type": "zip",
114 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
115 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
116 | "shasum": ""
117 | },
118 | "require": {
119 | "php": ">=5.3,<8.0-DEV"
120 | },
121 | "require-dev": {
122 | "athletic/athletic": "~0.1.8",
123 | "ext-pdo": "*",
124 | "ext-phar": "*",
125 | "phpunit/phpunit": "~4.0",
126 | "squizlabs/php_codesniffer": "~2.0"
127 | },
128 | "type": "library",
129 | "extra": {
130 | "branch-alias": {
131 | "dev-master": "1.0.x-dev"
132 | }
133 | },
134 | "autoload": {
135 | "psr-4": {
136 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
137 | }
138 | },
139 | "notification-url": "https://packagist.org/downloads/",
140 | "license": [
141 | "MIT"
142 | ],
143 | "authors": [
144 | {
145 | "name": "Marco Pivetta",
146 | "email": "ocramius@gmail.com",
147 | "homepage": "http://ocramius.github.com/"
148 | }
149 | ],
150 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
151 | "homepage": "https://github.com/doctrine/instantiator",
152 | "keywords": [
153 | "constructor",
154 | "instantiate"
155 | ],
156 | "time": "2015-06-14 21:17:01"
157 | },
158 | {
159 | "name": "phpdocumentor/reflection-common",
160 | "version": "1.0",
161 | "source": {
162 | "type": "git",
163 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
164 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
165 | },
166 | "dist": {
167 | "type": "zip",
168 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
169 | "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
170 | "shasum": ""
171 | },
172 | "require": {
173 | "php": ">=5.5"
174 | },
175 | "require-dev": {
176 | "phpunit/phpunit": "^4.6"
177 | },
178 | "type": "library",
179 | "extra": {
180 | "branch-alias": {
181 | "dev-master": "1.0.x-dev"
182 | }
183 | },
184 | "autoload": {
185 | "psr-4": {
186 | "phpDocumentor\\Reflection\\": [
187 | "src"
188 | ]
189 | }
190 | },
191 | "notification-url": "https://packagist.org/downloads/",
192 | "license": [
193 | "MIT"
194 | ],
195 | "authors": [
196 | {
197 | "name": "Jaap van Otterdijk",
198 | "email": "opensource@ijaap.nl"
199 | }
200 | ],
201 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
202 | "homepage": "http://www.phpdoc.org",
203 | "keywords": [
204 | "FQSEN",
205 | "phpDocumentor",
206 | "phpdoc",
207 | "reflection",
208 | "static analysis"
209 | ],
210 | "time": "2015-12-27 11:43:31"
211 | },
212 | {
213 | "name": "phpdocumentor/reflection-docblock",
214 | "version": "3.1.0",
215 | "source": {
216 | "type": "git",
217 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
218 | "reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
219 | },
220 | "dist": {
221 | "type": "zip",
222 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
223 | "reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
224 | "shasum": ""
225 | },
226 | "require": {
227 | "php": ">=5.5",
228 | "phpdocumentor/reflection-common": "^1.0@dev",
229 | "phpdocumentor/type-resolver": "^0.2.0",
230 | "webmozart/assert": "^1.0"
231 | },
232 | "require-dev": {
233 | "mockery/mockery": "^0.9.4",
234 | "phpunit/phpunit": "^4.4"
235 | },
236 | "type": "library",
237 | "autoload": {
238 | "psr-4": {
239 | "phpDocumentor\\Reflection\\": [
240 | "src/"
241 | ]
242 | }
243 | },
244 | "notification-url": "https://packagist.org/downloads/",
245 | "license": [
246 | "MIT"
247 | ],
248 | "authors": [
249 | {
250 | "name": "Mike van Riel",
251 | "email": "me@mikevanriel.com"
252 | }
253 | ],
254 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
255 | "time": "2016-06-10 09:48:41"
256 | },
257 | {
258 | "name": "phpdocumentor/type-resolver",
259 | "version": "0.2",
260 | "source": {
261 | "type": "git",
262 | "url": "https://github.com/phpDocumentor/TypeResolver.git",
263 | "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
264 | },
265 | "dist": {
266 | "type": "zip",
267 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
268 | "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
269 | "shasum": ""
270 | },
271 | "require": {
272 | "php": ">=5.5",
273 | "phpdocumentor/reflection-common": "^1.0"
274 | },
275 | "require-dev": {
276 | "mockery/mockery": "^0.9.4",
277 | "phpunit/phpunit": "^5.2||^4.8.24"
278 | },
279 | "type": "library",
280 | "extra": {
281 | "branch-alias": {
282 | "dev-master": "1.0.x-dev"
283 | }
284 | },
285 | "autoload": {
286 | "psr-4": {
287 | "phpDocumentor\\Reflection\\": [
288 | "src/"
289 | ]
290 | }
291 | },
292 | "notification-url": "https://packagist.org/downloads/",
293 | "license": [
294 | "MIT"
295 | ],
296 | "authors": [
297 | {
298 | "name": "Mike van Riel",
299 | "email": "me@mikevanriel.com"
300 | }
301 | ],
302 | "time": "2016-06-10 07:14:17"
303 | },
304 | {
305 | "name": "phpspec/prophecy",
306 | "version": "v1.6.1",
307 | "source": {
308 | "type": "git",
309 | "url": "https://github.com/phpspec/prophecy.git",
310 | "reference": "58a8137754bc24b25740d4281399a4a3596058e0"
311 | },
312 | "dist": {
313 | "type": "zip",
314 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
315 | "reference": "58a8137754bc24b25740d4281399a4a3596058e0",
316 | "shasum": ""
317 | },
318 | "require": {
319 | "doctrine/instantiator": "^1.0.2",
320 | "php": "^5.3|^7.0",
321 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
322 | "sebastian/comparator": "^1.1",
323 | "sebastian/recursion-context": "^1.0"
324 | },
325 | "require-dev": {
326 | "phpspec/phpspec": "^2.0"
327 | },
328 | "type": "library",
329 | "extra": {
330 | "branch-alias": {
331 | "dev-master": "1.6.x-dev"
332 | }
333 | },
334 | "autoload": {
335 | "psr-0": {
336 | "Prophecy\\": "src/"
337 | }
338 | },
339 | "notification-url": "https://packagist.org/downloads/",
340 | "license": [
341 | "MIT"
342 | ],
343 | "authors": [
344 | {
345 | "name": "Konstantin Kudryashov",
346 | "email": "ever.zet@gmail.com",
347 | "homepage": "http://everzet.com"
348 | },
349 | {
350 | "name": "Marcello Duarte",
351 | "email": "marcello.duarte@gmail.com"
352 | }
353 | ],
354 | "description": "Highly opinionated mocking framework for PHP 5.3+",
355 | "homepage": "https://github.com/phpspec/prophecy",
356 | "keywords": [
357 | "Double",
358 | "Dummy",
359 | "fake",
360 | "mock",
361 | "spy",
362 | "stub"
363 | ],
364 | "time": "2016-06-07 08:13:47"
365 | },
366 | {
367 | "name": "phpunit/php-code-coverage",
368 | "version": "2.2.4",
369 | "source": {
370 | "type": "git",
371 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
372 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
373 | },
374 | "dist": {
375 | "type": "zip",
376 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
377 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
378 | "shasum": ""
379 | },
380 | "require": {
381 | "php": ">=5.3.3",
382 | "phpunit/php-file-iterator": "~1.3",
383 | "phpunit/php-text-template": "~1.2",
384 | "phpunit/php-token-stream": "~1.3",
385 | "sebastian/environment": "^1.3.2",
386 | "sebastian/version": "~1.0"
387 | },
388 | "require-dev": {
389 | "ext-xdebug": ">=2.1.4",
390 | "phpunit/phpunit": "~4"
391 | },
392 | "suggest": {
393 | "ext-dom": "*",
394 | "ext-xdebug": ">=2.2.1",
395 | "ext-xmlwriter": "*"
396 | },
397 | "type": "library",
398 | "extra": {
399 | "branch-alias": {
400 | "dev-master": "2.2.x-dev"
401 | }
402 | },
403 | "autoload": {
404 | "classmap": [
405 | "src/"
406 | ]
407 | },
408 | "notification-url": "https://packagist.org/downloads/",
409 | "license": [
410 | "BSD-3-Clause"
411 | ],
412 | "authors": [
413 | {
414 | "name": "Sebastian Bergmann",
415 | "email": "sb@sebastian-bergmann.de",
416 | "role": "lead"
417 | }
418 | ],
419 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
420 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
421 | "keywords": [
422 | "coverage",
423 | "testing",
424 | "xunit"
425 | ],
426 | "time": "2015-10-06 15:47:00"
427 | },
428 | {
429 | "name": "phpunit/php-file-iterator",
430 | "version": "1.4.1",
431 | "source": {
432 | "type": "git",
433 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
434 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
435 | },
436 | "dist": {
437 | "type": "zip",
438 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
439 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
440 | "shasum": ""
441 | },
442 | "require": {
443 | "php": ">=5.3.3"
444 | },
445 | "type": "library",
446 | "extra": {
447 | "branch-alias": {
448 | "dev-master": "1.4.x-dev"
449 | }
450 | },
451 | "autoload": {
452 | "classmap": [
453 | "src/"
454 | ]
455 | },
456 | "notification-url": "https://packagist.org/downloads/",
457 | "license": [
458 | "BSD-3-Clause"
459 | ],
460 | "authors": [
461 | {
462 | "name": "Sebastian Bergmann",
463 | "email": "sb@sebastian-bergmann.de",
464 | "role": "lead"
465 | }
466 | ],
467 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
468 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
469 | "keywords": [
470 | "filesystem",
471 | "iterator"
472 | ],
473 | "time": "2015-06-21 13:08:43"
474 | },
475 | {
476 | "name": "phpunit/php-text-template",
477 | "version": "1.2.1",
478 | "source": {
479 | "type": "git",
480 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
481 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
482 | },
483 | "dist": {
484 | "type": "zip",
485 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
486 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
487 | "shasum": ""
488 | },
489 | "require": {
490 | "php": ">=5.3.3"
491 | },
492 | "type": "library",
493 | "autoload": {
494 | "classmap": [
495 | "src/"
496 | ]
497 | },
498 | "notification-url": "https://packagist.org/downloads/",
499 | "license": [
500 | "BSD-3-Clause"
501 | ],
502 | "authors": [
503 | {
504 | "name": "Sebastian Bergmann",
505 | "email": "sebastian@phpunit.de",
506 | "role": "lead"
507 | }
508 | ],
509 | "description": "Simple template engine.",
510 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
511 | "keywords": [
512 | "template"
513 | ],
514 | "time": "2015-06-21 13:50:34"
515 | },
516 | {
517 | "name": "phpunit/php-timer",
518 | "version": "1.0.8",
519 | "source": {
520 | "type": "git",
521 | "url": "https://github.com/sebastianbergmann/php-timer.git",
522 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
523 | },
524 | "dist": {
525 | "type": "zip",
526 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
527 | "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
528 | "shasum": ""
529 | },
530 | "require": {
531 | "php": ">=5.3.3"
532 | },
533 | "require-dev": {
534 | "phpunit/phpunit": "~4|~5"
535 | },
536 | "type": "library",
537 | "autoload": {
538 | "classmap": [
539 | "src/"
540 | ]
541 | },
542 | "notification-url": "https://packagist.org/downloads/",
543 | "license": [
544 | "BSD-3-Clause"
545 | ],
546 | "authors": [
547 | {
548 | "name": "Sebastian Bergmann",
549 | "email": "sb@sebastian-bergmann.de",
550 | "role": "lead"
551 | }
552 | ],
553 | "description": "Utility class for timing",
554 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
555 | "keywords": [
556 | "timer"
557 | ],
558 | "time": "2016-05-12 18:03:57"
559 | },
560 | {
561 | "name": "phpunit/php-token-stream",
562 | "version": "1.4.8",
563 | "source": {
564 | "type": "git",
565 | "url": "https://github.com/sebastianbergmann/php-token-stream.git",
566 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
567 | },
568 | "dist": {
569 | "type": "zip",
570 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
571 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
572 | "shasum": ""
573 | },
574 | "require": {
575 | "ext-tokenizer": "*",
576 | "php": ">=5.3.3"
577 | },
578 | "require-dev": {
579 | "phpunit/phpunit": "~4.2"
580 | },
581 | "type": "library",
582 | "extra": {
583 | "branch-alias": {
584 | "dev-master": "1.4-dev"
585 | }
586 | },
587 | "autoload": {
588 | "classmap": [
589 | "src/"
590 | ]
591 | },
592 | "notification-url": "https://packagist.org/downloads/",
593 | "license": [
594 | "BSD-3-Clause"
595 | ],
596 | "authors": [
597 | {
598 | "name": "Sebastian Bergmann",
599 | "email": "sebastian@phpunit.de"
600 | }
601 | ],
602 | "description": "Wrapper around PHP's tokenizer extension.",
603 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
604 | "keywords": [
605 | "tokenizer"
606 | ],
607 | "time": "2015-09-15 10:49:45"
608 | },
609 | {
610 | "name": "phpunit/phpunit",
611 | "version": "4.8.27",
612 | "source": {
613 | "type": "git",
614 | "url": "https://github.com/sebastianbergmann/phpunit.git",
615 | "reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90"
616 | },
617 | "dist": {
618 | "type": "zip",
619 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c062dddcb68e44b563f66ee319ddae2b5a322a90",
620 | "reference": "c062dddcb68e44b563f66ee319ddae2b5a322a90",
621 | "shasum": ""
622 | },
623 | "require": {
624 | "ext-dom": "*",
625 | "ext-json": "*",
626 | "ext-pcre": "*",
627 | "ext-reflection": "*",
628 | "ext-spl": "*",
629 | "php": ">=5.3.3",
630 | "phpspec/prophecy": "^1.3.1",
631 | "phpunit/php-code-coverage": "~2.1",
632 | "phpunit/php-file-iterator": "~1.4",
633 | "phpunit/php-text-template": "~1.2",
634 | "phpunit/php-timer": "^1.0.6",
635 | "phpunit/phpunit-mock-objects": "~2.3",
636 | "sebastian/comparator": "~1.1",
637 | "sebastian/diff": "~1.2",
638 | "sebastian/environment": "~1.3",
639 | "sebastian/exporter": "~1.2",
640 | "sebastian/global-state": "~1.0",
641 | "sebastian/version": "~1.0",
642 | "symfony/yaml": "~2.1|~3.0"
643 | },
644 | "suggest": {
645 | "phpunit/php-invoker": "~1.1"
646 | },
647 | "bin": [
648 | "phpunit"
649 | ],
650 | "type": "library",
651 | "extra": {
652 | "branch-alias": {
653 | "dev-master": "4.8.x-dev"
654 | }
655 | },
656 | "autoload": {
657 | "classmap": [
658 | "src/"
659 | ]
660 | },
661 | "notification-url": "https://packagist.org/downloads/",
662 | "license": [
663 | "BSD-3-Clause"
664 | ],
665 | "authors": [
666 | {
667 | "name": "Sebastian Bergmann",
668 | "email": "sebastian@phpunit.de",
669 | "role": "lead"
670 | }
671 | ],
672 | "description": "The PHP Unit Testing framework.",
673 | "homepage": "https://phpunit.de/",
674 | "keywords": [
675 | "phpunit",
676 | "testing",
677 | "xunit"
678 | ],
679 | "time": "2016-07-21 06:48:14"
680 | },
681 | {
682 | "name": "phpunit/phpunit-mock-objects",
683 | "version": "2.3.8",
684 | "source": {
685 | "type": "git",
686 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
687 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
688 | },
689 | "dist": {
690 | "type": "zip",
691 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
692 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
693 | "shasum": ""
694 | },
695 | "require": {
696 | "doctrine/instantiator": "^1.0.2",
697 | "php": ">=5.3.3",
698 | "phpunit/php-text-template": "~1.2",
699 | "sebastian/exporter": "~1.2"
700 | },
701 | "require-dev": {
702 | "phpunit/phpunit": "~4.4"
703 | },
704 | "suggest": {
705 | "ext-soap": "*"
706 | },
707 | "type": "library",
708 | "extra": {
709 | "branch-alias": {
710 | "dev-master": "2.3.x-dev"
711 | }
712 | },
713 | "autoload": {
714 | "classmap": [
715 | "src/"
716 | ]
717 | },
718 | "notification-url": "https://packagist.org/downloads/",
719 | "license": [
720 | "BSD-3-Clause"
721 | ],
722 | "authors": [
723 | {
724 | "name": "Sebastian Bergmann",
725 | "email": "sb@sebastian-bergmann.de",
726 | "role": "lead"
727 | }
728 | ],
729 | "description": "Mock Object library for PHPUnit",
730 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
731 | "keywords": [
732 | "mock",
733 | "xunit"
734 | ],
735 | "time": "2015-10-02 06:51:40"
736 | },
737 | {
738 | "name": "sebastian/comparator",
739 | "version": "1.2.0",
740 | "source": {
741 | "type": "git",
742 | "url": "https://github.com/sebastianbergmann/comparator.git",
743 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
744 | },
745 | "dist": {
746 | "type": "zip",
747 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
748 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
749 | "shasum": ""
750 | },
751 | "require": {
752 | "php": ">=5.3.3",
753 | "sebastian/diff": "~1.2",
754 | "sebastian/exporter": "~1.2"
755 | },
756 | "require-dev": {
757 | "phpunit/phpunit": "~4.4"
758 | },
759 | "type": "library",
760 | "extra": {
761 | "branch-alias": {
762 | "dev-master": "1.2.x-dev"
763 | }
764 | },
765 | "autoload": {
766 | "classmap": [
767 | "src/"
768 | ]
769 | },
770 | "notification-url": "https://packagist.org/downloads/",
771 | "license": [
772 | "BSD-3-Clause"
773 | ],
774 | "authors": [
775 | {
776 | "name": "Jeff Welch",
777 | "email": "whatthejeff@gmail.com"
778 | },
779 | {
780 | "name": "Volker Dusch",
781 | "email": "github@wallbash.com"
782 | },
783 | {
784 | "name": "Bernhard Schussek",
785 | "email": "bschussek@2bepublished.at"
786 | },
787 | {
788 | "name": "Sebastian Bergmann",
789 | "email": "sebastian@phpunit.de"
790 | }
791 | ],
792 | "description": "Provides the functionality to compare PHP values for equality",
793 | "homepage": "http://www.github.com/sebastianbergmann/comparator",
794 | "keywords": [
795 | "comparator",
796 | "compare",
797 | "equality"
798 | ],
799 | "time": "2015-07-26 15:48:44"
800 | },
801 | {
802 | "name": "sebastian/diff",
803 | "version": "1.4.1",
804 | "source": {
805 | "type": "git",
806 | "url": "https://github.com/sebastianbergmann/diff.git",
807 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
808 | },
809 | "dist": {
810 | "type": "zip",
811 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
812 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
813 | "shasum": ""
814 | },
815 | "require": {
816 | "php": ">=5.3.3"
817 | },
818 | "require-dev": {
819 | "phpunit/phpunit": "~4.8"
820 | },
821 | "type": "library",
822 | "extra": {
823 | "branch-alias": {
824 | "dev-master": "1.4-dev"
825 | }
826 | },
827 | "autoload": {
828 | "classmap": [
829 | "src/"
830 | ]
831 | },
832 | "notification-url": "https://packagist.org/downloads/",
833 | "license": [
834 | "BSD-3-Clause"
835 | ],
836 | "authors": [
837 | {
838 | "name": "Kore Nordmann",
839 | "email": "mail@kore-nordmann.de"
840 | },
841 | {
842 | "name": "Sebastian Bergmann",
843 | "email": "sebastian@phpunit.de"
844 | }
845 | ],
846 | "description": "Diff implementation",
847 | "homepage": "https://github.com/sebastianbergmann/diff",
848 | "keywords": [
849 | "diff"
850 | ],
851 | "time": "2015-12-08 07:14:41"
852 | },
853 | {
854 | "name": "sebastian/environment",
855 | "version": "1.3.8",
856 | "source": {
857 | "type": "git",
858 | "url": "https://github.com/sebastianbergmann/environment.git",
859 | "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
860 | },
861 | "dist": {
862 | "type": "zip",
863 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
864 | "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
865 | "shasum": ""
866 | },
867 | "require": {
868 | "php": "^5.3.3 || ^7.0"
869 | },
870 | "require-dev": {
871 | "phpunit/phpunit": "^4.8 || ^5.0"
872 | },
873 | "type": "library",
874 | "extra": {
875 | "branch-alias": {
876 | "dev-master": "1.3.x-dev"
877 | }
878 | },
879 | "autoload": {
880 | "classmap": [
881 | "src/"
882 | ]
883 | },
884 | "notification-url": "https://packagist.org/downloads/",
885 | "license": [
886 | "BSD-3-Clause"
887 | ],
888 | "authors": [
889 | {
890 | "name": "Sebastian Bergmann",
891 | "email": "sebastian@phpunit.de"
892 | }
893 | ],
894 | "description": "Provides functionality to handle HHVM/PHP environments",
895 | "homepage": "http://www.github.com/sebastianbergmann/environment",
896 | "keywords": [
897 | "Xdebug",
898 | "environment",
899 | "hhvm"
900 | ],
901 | "time": "2016-08-18 05:49:44"
902 | },
903 | {
904 | "name": "sebastian/exporter",
905 | "version": "1.2.2",
906 | "source": {
907 | "type": "git",
908 | "url": "https://github.com/sebastianbergmann/exporter.git",
909 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
910 | },
911 | "dist": {
912 | "type": "zip",
913 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
914 | "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
915 | "shasum": ""
916 | },
917 | "require": {
918 | "php": ">=5.3.3",
919 | "sebastian/recursion-context": "~1.0"
920 | },
921 | "require-dev": {
922 | "ext-mbstring": "*",
923 | "phpunit/phpunit": "~4.4"
924 | },
925 | "type": "library",
926 | "extra": {
927 | "branch-alias": {
928 | "dev-master": "1.3.x-dev"
929 | }
930 | },
931 | "autoload": {
932 | "classmap": [
933 | "src/"
934 | ]
935 | },
936 | "notification-url": "https://packagist.org/downloads/",
937 | "license": [
938 | "BSD-3-Clause"
939 | ],
940 | "authors": [
941 | {
942 | "name": "Jeff Welch",
943 | "email": "whatthejeff@gmail.com"
944 | },
945 | {
946 | "name": "Volker Dusch",
947 | "email": "github@wallbash.com"
948 | },
949 | {
950 | "name": "Bernhard Schussek",
951 | "email": "bschussek@2bepublished.at"
952 | },
953 | {
954 | "name": "Sebastian Bergmann",
955 | "email": "sebastian@phpunit.de"
956 | },
957 | {
958 | "name": "Adam Harvey",
959 | "email": "aharvey@php.net"
960 | }
961 | ],
962 | "description": "Provides the functionality to export PHP variables for visualization",
963 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
964 | "keywords": [
965 | "export",
966 | "exporter"
967 | ],
968 | "time": "2016-06-17 09:04:28"
969 | },
970 | {
971 | "name": "sebastian/global-state",
972 | "version": "1.1.1",
973 | "source": {
974 | "type": "git",
975 | "url": "https://github.com/sebastianbergmann/global-state.git",
976 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
977 | },
978 | "dist": {
979 | "type": "zip",
980 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
981 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
982 | "shasum": ""
983 | },
984 | "require": {
985 | "php": ">=5.3.3"
986 | },
987 | "require-dev": {
988 | "phpunit/phpunit": "~4.2"
989 | },
990 | "suggest": {
991 | "ext-uopz": "*"
992 | },
993 | "type": "library",
994 | "extra": {
995 | "branch-alias": {
996 | "dev-master": "1.0-dev"
997 | }
998 | },
999 | "autoload": {
1000 | "classmap": [
1001 | "src/"
1002 | ]
1003 | },
1004 | "notification-url": "https://packagist.org/downloads/",
1005 | "license": [
1006 | "BSD-3-Clause"
1007 | ],
1008 | "authors": [
1009 | {
1010 | "name": "Sebastian Bergmann",
1011 | "email": "sebastian@phpunit.de"
1012 | }
1013 | ],
1014 | "description": "Snapshotting of global state",
1015 | "homepage": "http://www.github.com/sebastianbergmann/global-state",
1016 | "keywords": [
1017 | "global state"
1018 | ],
1019 | "time": "2015-10-12 03:26:01"
1020 | },
1021 | {
1022 | "name": "sebastian/recursion-context",
1023 | "version": "1.0.2",
1024 | "source": {
1025 | "type": "git",
1026 | "url": "https://github.com/sebastianbergmann/recursion-context.git",
1027 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791"
1028 | },
1029 | "dist": {
1030 | "type": "zip",
1031 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
1032 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791",
1033 | "shasum": ""
1034 | },
1035 | "require": {
1036 | "php": ">=5.3.3"
1037 | },
1038 | "require-dev": {
1039 | "phpunit/phpunit": "~4.4"
1040 | },
1041 | "type": "library",
1042 | "extra": {
1043 | "branch-alias": {
1044 | "dev-master": "1.0.x-dev"
1045 | }
1046 | },
1047 | "autoload": {
1048 | "classmap": [
1049 | "src/"
1050 | ]
1051 | },
1052 | "notification-url": "https://packagist.org/downloads/",
1053 | "license": [
1054 | "BSD-3-Clause"
1055 | ],
1056 | "authors": [
1057 | {
1058 | "name": "Jeff Welch",
1059 | "email": "whatthejeff@gmail.com"
1060 | },
1061 | {
1062 | "name": "Sebastian Bergmann",
1063 | "email": "sebastian@phpunit.de"
1064 | },
1065 | {
1066 | "name": "Adam Harvey",
1067 | "email": "aharvey@php.net"
1068 | }
1069 | ],
1070 | "description": "Provides functionality to recursively process PHP variables",
1071 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
1072 | "time": "2015-11-11 19:50:13"
1073 | },
1074 | {
1075 | "name": "sebastian/version",
1076 | "version": "1.0.6",
1077 | "source": {
1078 | "type": "git",
1079 | "url": "https://github.com/sebastianbergmann/version.git",
1080 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
1081 | },
1082 | "dist": {
1083 | "type": "zip",
1084 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1085 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
1086 | "shasum": ""
1087 | },
1088 | "type": "library",
1089 | "autoload": {
1090 | "classmap": [
1091 | "src/"
1092 | ]
1093 | },
1094 | "notification-url": "https://packagist.org/downloads/",
1095 | "license": [
1096 | "BSD-3-Clause"
1097 | ],
1098 | "authors": [
1099 | {
1100 | "name": "Sebastian Bergmann",
1101 | "email": "sebastian@phpunit.de",
1102 | "role": "lead"
1103 | }
1104 | ],
1105 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
1106 | "homepage": "https://github.com/sebastianbergmann/version",
1107 | "time": "2015-06-21 13:59:46"
1108 | },
1109 | {
1110 | "name": "symfony/yaml",
1111 | "version": "v3.1.3",
1112 | "source": {
1113 | "type": "git",
1114 | "url": "https://github.com/symfony/yaml.git",
1115 | "reference": "1819adf2066880c7967df7180f4f662b6f0567ac"
1116 | },
1117 | "dist": {
1118 | "type": "zip",
1119 | "url": "https://api.github.com/repos/symfony/yaml/zipball/1819adf2066880c7967df7180f4f662b6f0567ac",
1120 | "reference": "1819adf2066880c7967df7180f4f662b6f0567ac",
1121 | "shasum": ""
1122 | },
1123 | "require": {
1124 | "php": ">=5.5.9"
1125 | },
1126 | "type": "library",
1127 | "extra": {
1128 | "branch-alias": {
1129 | "dev-master": "3.1-dev"
1130 | }
1131 | },
1132 | "autoload": {
1133 | "psr-4": {
1134 | "Symfony\\Component\\Yaml\\": ""
1135 | },
1136 | "exclude-from-classmap": [
1137 | "/Tests/"
1138 | ]
1139 | },
1140 | "notification-url": "https://packagist.org/downloads/",
1141 | "license": [
1142 | "MIT"
1143 | ],
1144 | "authors": [
1145 | {
1146 | "name": "Fabien Potencier",
1147 | "email": "fabien@symfony.com"
1148 | },
1149 | {
1150 | "name": "Symfony Community",
1151 | "homepage": "https://symfony.com/contributors"
1152 | }
1153 | ],
1154 | "description": "Symfony Yaml Component",
1155 | "homepage": "https://symfony.com",
1156 | "time": "2016-07-17 14:02:08"
1157 | },
1158 | {
1159 | "name": "webmozart/assert",
1160 | "version": "1.1.0",
1161 | "source": {
1162 | "type": "git",
1163 | "url": "https://github.com/webmozart/assert.git",
1164 | "reference": "bb2d123231c095735130cc8f6d31385a44c7b308"
1165 | },
1166 | "dist": {
1167 | "type": "zip",
1168 | "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308",
1169 | "reference": "bb2d123231c095735130cc8f6d31385a44c7b308",
1170 | "shasum": ""
1171 | },
1172 | "require": {
1173 | "php": "^5.3.3|^7.0"
1174 | },
1175 | "require-dev": {
1176 | "phpunit/phpunit": "^4.6",
1177 | "sebastian/version": "^1.0.1"
1178 | },
1179 | "type": "library",
1180 | "extra": {
1181 | "branch-alias": {
1182 | "dev-master": "1.2-dev"
1183 | }
1184 | },
1185 | "autoload": {
1186 | "psr-4": {
1187 | "Webmozart\\Assert\\": "src/"
1188 | }
1189 | },
1190 | "notification-url": "https://packagist.org/downloads/",
1191 | "license": [
1192 | "MIT"
1193 | ],
1194 | "authors": [
1195 | {
1196 | "name": "Bernhard Schussek",
1197 | "email": "bschussek@gmail.com"
1198 | }
1199 | ],
1200 | "description": "Assertions to validate method input/output with nice error messages.",
1201 | "keywords": [
1202 | "assert",
1203 | "check",
1204 | "validate"
1205 | ],
1206 | "time": "2016-08-09 15:02:57"
1207 | }
1208 | ],
1209 | "aliases": [],
1210 | "minimum-stability": "stable",
1211 | "stability-flags": [],
1212 | "prefer-stable": false,
1213 | "prefer-lowest": false,
1214 | "platform": {
1215 | "php": ">=5.6"
1216 | },
1217 | "platform-dev": []
1218 | }
1219 |
--------------------------------------------------------------------------------
/example/IdToken.php:
--------------------------------------------------------------------------------
1 | jwt = new JOSE_JWT($claims);
10 | }
11 |
12 | function sign($private_key_or_secret, $algorithm = 'RS256') {
13 | $this->jwt = $this->jwt->sign($private_key_or_secret, $algorithm);
14 | return $this;
15 | }
16 |
17 | function toString() {
18 | return $this->jwt->toString();
19 | }
20 | }
21 |
22 | $public_key = file_get_contents(dirname(__FILE__) . '/../test/fixtures/public_key.pem');
23 | $private_key = file_get_contents(dirname(__FILE__) . '/../test/fixtures/private_key.pem');
24 |
25 | $id_token = new IdToken(array(
26 | 'iss' => 'https://gree.net',
27 | 'aud' => 'greeapp_12345',
28 | 'sub' => 'greeuser_12345',
29 | 'iat' => time(),
30 | 'exp' => time() + 1 * 60 * 60
31 | ));
32 | $id_token->sign($private_key);
33 |
34 | echo $id_token->toString();
--------------------------------------------------------------------------------
/src/JOSE/Exception.php:
--------------------------------------------------------------------------------
1 | raw = $input->toString();
21 | } else {
22 | $this->raw = $input;
23 | }
24 | unset($this->header['typ']);
25 | }
26 |
27 | function encrypt($public_key_or_secret, $algorithm = 'RSA1_5', $encryption_method = 'A128CBC-HS256') {
28 | $this->header['alg'] = $algorithm;
29 | $this->header['enc'] = $encryption_method;
30 | if (
31 | $public_key_or_secret instanceof JOSE_JWK &&
32 | !array_key_exists('kid', $this->header) &&
33 | array_key_exists('kid', $public_key_or_secret->components)
34 | ) {
35 | $this->header['kid'] = $public_key_or_secret->components['kid'];
36 | }
37 | $this->plain_text = $this->raw;
38 | $this->generateContentEncryptionKey($public_key_or_secret);
39 | $this->encryptContentEncryptionKey($public_key_or_secret);
40 | $this->generateIv();
41 | $this->deriveEncryptionAndMacKeys();
42 | $this->encryptCipherText();
43 | $this->generateAuthenticationTag();
44 | return $this;
45 | }
46 |
47 | function decrypt($private_key_or_secret) {
48 | $this->decryptContentEncryptionKey($private_key_or_secret);
49 | $this->deriveEncryptionAndMacKeys();
50 | $this->decryptCipherText();
51 | $this->checkAuthenticationTag();
52 | return $this;
53 | }
54 |
55 | function toString() {
56 | return implode('.', array(
57 | $this->compact((object) $this->header),
58 | $this->compact($this->jwe_encrypted_key),
59 | $this->compact($this->iv),
60 | $this->compact($this->cipher_text),
61 | $this->compact($this->authentication_tag)
62 | ));
63 | }
64 |
65 | private function rsa($public_or_private_key, $padding_mode) {
66 | if ($public_or_private_key instanceof JOSE_JWK) {
67 | $rsa = $public_or_private_key->toKey();
68 | } else if ($public_or_private_key instanceof RSA) {
69 | $rsa = $public_or_private_key;
70 | } else {
71 | $rsa = new RSA();
72 | $rsa->loadKey($public_or_private_key);
73 | }
74 | $rsa->setEncryptionMode($padding_mode);
75 | return $rsa;
76 | }
77 |
78 | private function cipher() {
79 | switch ($this->header['enc']) {
80 | case 'A128GCM':
81 | case 'A256GCM':
82 | throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported');
83 | case 'A128CBC-HS256':
84 | case 'A256CBC-HS512':
85 | $cipher = new AES(AES::MODE_CBC);
86 | break;
87 | default:
88 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
89 | }
90 | switch ($this->header['enc']) {
91 | case 'A128GCM':
92 | case 'A128CBC-HS256':
93 | $cipher->setBlockLength(128);
94 | break;
95 | case 'A256GCM':
96 | case 'A256CBC-HS512':
97 | $cipher->setBlockLength(256);
98 | break;
99 | default:
100 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
101 | }
102 | return $cipher;
103 | }
104 |
105 | private function generateRandomBytes($length) {
106 | return Random::string($length);
107 | }
108 |
109 | private function generateIv() {
110 | switch ($this->header['enc']) {
111 | case 'A128GCM':
112 | case 'A128CBC-HS256':
113 | $this->iv = $this->generateRandomBytes(128 / 8);
114 | break;
115 | case 'A256GCM':
116 | case 'A256CBC-HS512':
117 | $this->iv = $this->generateRandomBytes(256 / 8);
118 | break;
119 | default:
120 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
121 | }
122 | }
123 |
124 | private function generateContentEncryptionKey($public_key_or_secret) {
125 | if ($this->header['alg'] == 'dir') {
126 | $this->content_encryption_key = $public_key_or_secret;
127 | } else {
128 | switch ($this->header['enc']) {
129 | case 'A128GCM':
130 | case 'A128CBC-HS256':
131 | $this->content_encryption_key = $this->generateRandomBytes(256 / 8);
132 | break;
133 | case 'A256GCM':
134 | case 'A256CBC-HS512':
135 | $this->content_encryption_key = $this->generateRandomBytes(512 / 8);
136 | break;
137 | default:
138 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
139 | }
140 | }
141 | }
142 |
143 | private function encryptContentEncryptionKey($public_key_or_secret) {
144 | switch ($this->header['alg']) {
145 | case 'RSA1_5':
146 | $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_PKCS1);
147 | $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key);
148 | break;
149 | case 'RSA-OAEP':
150 | $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_OAEP);
151 | $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key);
152 | break;
153 | case 'dir':
154 | $this->jwe_encrypted_key = '';
155 | return;
156 | case 'A128KW':
157 | case 'A256KW':
158 | case 'ECDH-ES':
159 | case 'ECDH-ES+A128KW':
160 | case 'ECDH-ES+A256KW':
161 | throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported');
162 | default:
163 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
164 | }
165 | if (!$this->jwe_encrypted_key) {
166 | throw new JOSE_Exception_EncryptionFailed('Master key encryption failed');
167 | }
168 | }
169 |
170 | private function decryptContentEncryptionKey($private_key_or_secret) {
171 | $this->generateContentEncryptionKey(null); # NOTE: run this always not to make timing difference
172 | $fake_content_encryption_key = $this->content_encryption_key;
173 | switch ($this->header['alg']) {
174 | case 'RSA1_5':
175 | $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_PKCS1);
176 | $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key);
177 | break;
178 | case 'RSA-OAEP':
179 | $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_OAEP);
180 | $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key);
181 | break;
182 | case 'dir':
183 | $this->content_encryption_key = $private_key_or_secret;
184 | break;
185 | case 'A128KW':
186 | case 'A256KW':
187 | case 'ECDH-ES':
188 | case 'ECDH-ES+A128KW':
189 | case 'ECDH-ES+A256KW':
190 | throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported');
191 | default:
192 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
193 | }
194 | if (!$this->content_encryption_key) {
195 | # NOTE:
196 | # Not to disclose timing difference between CEK decryption error and others.
197 | # Mitigating Bleichenbacher Attack on PKCS#1 v1.5
198 | # ref.) http://inaz2.hatenablog.com/entry/2016/01/26/222303
199 | $this->content_encryption_key = $fake_content_encryption_key;
200 | }
201 | }
202 |
203 | private function deriveEncryptionAndMacKeys() {
204 | switch ($this->header['enc']) {
205 | case 'A128GCM':
206 | case 'A256GCM':
207 | $this->encryption_key = $this->content_encryption_key;
208 | $this->mac_key = "won't be used";
209 | break;
210 | case 'A128CBC-HS256':
211 | $this->deriveEncryptionAndMacKeysCBC(256);
212 | break;
213 | case 'A256CBC-HS512':
214 | $this->deriveEncryptionAndMacKeysCBC(512);
215 | break;
216 | default:
217 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
218 | }
219 | if (!$this->encryption_key || !$this->mac_key) {
220 | throw new JOSE_Exception_DecryptionFailed('Encryption/Mac key derivation failed');
221 | }
222 | }
223 |
224 | private function deriveEncryptionAndMacKeysCBC($sha_size) {
225 | $this->mac_key = substr($this->content_encryption_key, 0, $sha_size / 2 / 8);
226 | $this->encryption_key = substr($this->content_encryption_key, $sha_size / 2 / 8);
227 | }
228 |
229 | private function encryptCipherText() {
230 | $cipher = $this->cipher();
231 | $cipher->setKey($this->encryption_key);
232 | $cipher->setIV($this->iv);
233 | $this->cipher_text = $cipher->encrypt($this->plain_text);
234 | if (!$this->cipher_text) {
235 | throw new JOSE_Exception_DecryptionFailed('Payload encryption failed');
236 | }
237 | }
238 |
239 | private function decryptCipherText() {
240 | $cipher = $this->cipher();
241 | $cipher->setKey($this->encryption_key);
242 | $cipher->setIV($this->iv);
243 | $this->plain_text = $cipher->decrypt($this->cipher_text);
244 | if (!$this->plain_text) {
245 | throw new JOSE_Exception_DecryptionFailed('Payload decryption failed');
246 | }
247 | }
248 |
249 | private function generateAuthenticationTag() {
250 | $this->authentication_tag = $this->calculateAuthenticationTag();
251 | }
252 |
253 | private function calculateAuthenticationTag($use_raw = false) {
254 | switch ($this->header['enc']) {
255 | case 'A128GCM':
256 | case 'A256GCM':
257 | throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported');
258 | case 'A128CBC-HS256':
259 | return $this->calculateAuthenticationTagCBC(256);
260 | case 'A256CBC-HS512':
261 | return $this->calculateAuthenticationTagCBC(512);
262 | default:
263 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
264 | }
265 | }
266 |
267 | private function calculateAuthenticationTagCBC($sha_size) {
268 | if (!$this->auth_data) {
269 | $this->auth_data = $this->compact((object) $this->header);
270 | }
271 | $auth_data_length = strlen($this->auth_data);
272 | $max_32bit = 2147483647;
273 | $secured_input = implode('', array(
274 | $this->auth_data,
275 | $this->iv,
276 | $this->cipher_text,
277 | // NOTE: PHP doesn't support 64bit big endian, so handling upper & lower 32bit.
278 | pack('N2', ($auth_data_length / $max_32bit) * 8, ($auth_data_length % $max_32bit) * 8)
279 | ));
280 | return substr(
281 | hash_hmac('sha' . $sha_size, $secured_input, $this->mac_key, true),
282 | 0, $sha_size / 2 / 8
283 | );
284 | }
285 |
286 | private function checkAuthenticationTag() {
287 | if (hash_equals($this->authentication_tag, $this->calculateAuthenticationTag())) {
288 | return true;
289 | } else {
290 | throw new JOSE_Exception_UnexpectedAlgorithm('Invalid authentication tag');
291 | }
292 | }
293 | }
294 |
--------------------------------------------------------------------------------
/src/JOSE/JWK.php:
--------------------------------------------------------------------------------
1 | components = $components;
15 | if (!array_key_exists('kid', $this->components)) {
16 | $this->components['kid'] = $this->thumbprint();
17 | }
18 | }
19 |
20 | function toKey() {
21 | switch ($this->components['kty']) {
22 | case 'RSA':
23 | $rsa = new RSA();
24 | $n = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['n'])), 16);
25 | $e = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['e'])), 16);
26 | if (array_key_exists('d', $this->components)) {
27 | throw new JOSE_Exception_UnexpectedAlgorithm('RSA private key isn\'t supported');
28 | } else {
29 | $pem_string = $rsa->_convertPublicKey($n, $e);
30 | }
31 | $rsa->loadKey($pem_string);
32 | return $rsa;
33 | default:
34 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type');
35 | }
36 | }
37 |
38 | function thumbprint($hash_algorithm = 'sha256') {
39 | $hash = new Hash($hash_algorithm);
40 | return JOSE_URLSafeBase64::encode(
41 | $hash->hash(
42 | json_encode($this->normalized())
43 | )
44 | );
45 | }
46 |
47 | private function normalized() {
48 | switch ($this->components['kty']) {
49 | case 'RSA':
50 | return array(
51 | 'e' => $this->components['e'],
52 | 'kty' => $this->components['kty'],
53 | 'n' => $this->components['n']
54 | );
55 | default:
56 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type');
57 | }
58 | }
59 |
60 | function toString() {
61 | return json_encode($this->components);
62 | }
63 | function __toString() {
64 | return $this->toString();
65 | }
66 |
67 | static function encode($key, $extra_components = array()) {
68 | switch(get_class($key)) {
69 | case 'phpseclib\Crypt\RSA':
70 | $components = array(
71 | 'kty' => 'RSA',
72 | 'e' => JOSE_URLSafeBase64::encode($key->publicExponent->toBytes()),
73 | 'n' => JOSE_URLSafeBase64::encode($key->modulus->toBytes())
74 | );
75 | if ($key->exponent != $key->publicExponent) {
76 | $components = array_merge($components, array(
77 | 'd' => JOSE_URLSafeBase64::encode($key->exponent->toBytes())
78 | ));
79 | }
80 | return new self(array_merge($components, $extra_components));
81 | default:
82 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown key type');
83 | }
84 | }
85 |
86 | static function decode($components) {
87 | $jwk = new self($components);
88 | return $jwk->toKey();
89 | }
90 | }
--------------------------------------------------------------------------------
/src/JOSE/JWKSet.php:
--------------------------------------------------------------------------------
1 | keys = $keys;
11 | }
12 |
13 | function toString() {
14 | $keys = array();
15 | foreach($this->keys as $key) {
16 | if ($key instanceof JOSE_JWK) {
17 | $keys[] = $key->components;
18 | } else {
19 | $keys[] = $key;
20 | }
21 | }
22 | return json_encode(array('keys' => $keys));
23 | }
24 | function __toString() {
25 | return $this->toString();
26 | }
27 | }
--------------------------------------------------------------------------------
/src/JOSE/JWS.php:
--------------------------------------------------------------------------------
1 | header = $jwt->header;
8 | $this->claims = $jwt->claims;
9 | $this->signature = $jwt->signature;
10 | $this->raw = $jwt->raw;
11 | }
12 |
13 | function toJson($syntax = 'flattened') {
14 | if ($syntax == 'flattened') {
15 | $components = array(
16 | 'protected' => $this->compact((object) $this->header),
17 | 'payload' => $this->compact((object) $this->claims),
18 | 'signature' => $this->compact($this->signature)
19 | );
20 | } else {
21 | $components = array(
22 | 'payload' => $this->compact((object) $this->claims),
23 | 'signatures' => array(
24 | 'protected' => $this->compact((object) $this->header),
25 | 'signature' => $this->compact($this->signature)
26 | )
27 | );
28 | }
29 | return json_encode($components);
30 | }
31 |
32 | function sign($private_key_or_secret, $algorithm = 'HS256') {
33 | $this->header['alg'] = $algorithm;
34 | if (
35 | $private_key_or_secret instanceof JOSE_JWK &&
36 | !array_key_exists('kid', $this->header) &&
37 | array_key_exists('kid', $private_key_or_secret->components)
38 | ) {
39 | $this->header['kid'] = $private_key_or_secret->components['kid'];
40 | }
41 | $this->signature = $this->_sign($private_key_or_secret);
42 | if (!$this->signature) {
43 | throw new JOSE_Exception('Signing failed because of unknown reason');
44 | }
45 | return $this;
46 | }
47 |
48 | function verify($public_key_or_secret, $alg = null) {
49 | if ($this->_verify($public_key_or_secret, $alg)) {
50 | return $this;
51 | } else {
52 | throw new JOSE_Exception_VerificationFailed('Signature verification failed');
53 | }
54 | }
55 |
56 | private function rsa($public_or_private_key, $padding_mode) {
57 | if ($public_or_private_key instanceof JOSE_JWK) {
58 | $rsa = $public_or_private_key->toKey();
59 | } else if ($public_or_private_key instanceof RSA) {
60 | $rsa = $public_or_private_key;
61 | } else {
62 | $rsa = new RSA();
63 | $rsa->loadKey($public_or_private_key);
64 | }
65 | $rsa->setHash($this->digest());
66 | $rsa->setMGFHash($this->digest());
67 | $rsa->setSignatureMode($padding_mode);
68 | return $rsa;
69 | }
70 |
71 | private function digest() {
72 | switch ($this->header['alg']) {
73 | case 'HS256':
74 | case 'RS256':
75 | case 'ES256':
76 | case 'PS256':
77 | return 'sha256';
78 | case 'HS384':
79 | case 'RS384':
80 | case 'ES384':
81 | case 'PS384':
82 | return 'sha384';
83 | case 'HS512':
84 | case 'RS512':
85 | case 'ES512':
86 | case 'PS512':
87 | return 'sha512';
88 | default:
89 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
90 | }
91 | }
92 |
93 | private function _sign($private_key_or_secret) {
94 | $signature_base_string = implode('.', array(
95 | $this->compact((object) $this->header),
96 | $this->compact((object) $this->claims)
97 | ));
98 | switch ($this->header['alg']) {
99 | case 'HS256':
100 | case 'HS384':
101 | case 'HS512':
102 | return hash_hmac($this->digest(), $signature_base_string, $private_key_or_secret, true);
103 | case 'RS256':
104 | case 'RS384':
105 | case 'RS512':
106 | return $this->rsa($private_key_or_secret, RSA::SIGNATURE_PKCS1)->sign($signature_base_string);
107 | case 'ES256':
108 | case 'ES384':
109 | case 'ES512':
110 | throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported');
111 | case 'PS256':
112 | case 'PS384':
113 | case 'PS512':
114 | return $this->rsa($private_key_or_secret, RSA::SIGNATURE_PSS)->sign($signature_base_string);
115 | default:
116 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
117 | }
118 | }
119 |
120 | private function _verify($public_key_or_secret, $expected_alg = null) {
121 | $segments = explode('.', $this->raw);
122 | $signature_base_string = implode('.', array($segments[0], $segments[1]));
123 | if (!$expected_alg) {
124 | $expected_alg = $this->header['alg'];
125 | $using_autodetected_alg = true;
126 | }
127 | switch ($expected_alg) {
128 | case 'HS256':
129 | case 'HS384':
130 | case 'HS512':
131 | if (isset($using_autodetected_alg)) {
132 | throw new JOSE_Exception_UnexpectedAlgorithm(
133 | 'HMAC algs MUST be explicitly specified as $expected_alg'
134 | );
135 | }
136 | $hmac_hash = hash_hmac($this->digest(), $signature_base_string, $public_key_or_secret, true);
137 | return hash_equals($this->signature, $hmac_hash);
138 | case 'RS256':
139 | case 'RS384':
140 | case 'RS512':
141 | return $this->rsa($public_key_or_secret, RSA::SIGNATURE_PKCS1)->verify($signature_base_string, $this->signature);
142 | case 'ES256':
143 | case 'ES384':
144 | case 'ES512':
145 | throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported');
146 | case 'PS256':
147 | case 'PS384':
148 | case 'PS512':
149 | return $this->rsa($public_key_or_secret, RSA::SIGNATURE_PSS)->verify($signature_base_string, $this->signature);
150 | default:
151 | throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm');
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/src/JOSE/JWT.php:
--------------------------------------------------------------------------------
1 | 'JWT',
6 | 'alg' => 'none'
7 | );
8 | var $claims = array();
9 | var $signature = '';
10 | var $raw;
11 |
12 | function __construct($claims = array()) {
13 | $this->claims = $claims;
14 | }
15 |
16 | function toString() {
17 | return implode('.', array(
18 | $this->compact((object) $this->header),
19 | $this->compact((object) $this->claims),
20 | $this->compact($this->signature)
21 | ));
22 | }
23 |
24 | function __toString() {
25 | return $this->toString();
26 | }
27 |
28 | function sign($private_key_or_secret, $algorithm = 'HS256') {
29 | $jws = $this->toJWS();
30 | $jws->sign($private_key_or_secret, $algorithm);
31 | return $jws;
32 | }
33 |
34 | function verify($public_key_or_secret, $alg = null) {
35 | $jws = $this->toJWS();
36 | $jws->verify($public_key_or_secret, $alg);
37 | return $jws;
38 | }
39 |
40 | function encrypt($public_key_or_secret, $algorithm = 'RSA1_5', $encryption_method = 'A128CBC-HS256') {
41 | $jwe = new JOSE_JWE($this);
42 | $jwe->encrypt($public_key_or_secret, $algorithm, $encryption_method);
43 | return $jwe;
44 | }
45 |
46 | static function encode($claims) {
47 | return new self($claims);
48 | }
49 |
50 | static function decode($jwt_string) {
51 | $segments = explode('.', $jwt_string);
52 | switch (count($segments)) {
53 | case 3:
54 | $jwt = new self();
55 | $jwt->raw = $jwt_string;
56 | $jwt->header = (array) $jwt->extract($segments[0]);
57 | $jwt->claims = (array) $jwt->extract($segments[1]);
58 | $jwt->signature = $jwt->extract($segments[2], 'as_binary');
59 | return $jwt;
60 | case 5:
61 | $jwe = new JOSE_JWE($jwt_string);
62 | $jwe->auth_data = $segments[0];
63 | $jwe->header = (array) $jwe->extract($segments[0]);
64 | $jwe->jwe_encrypted_key = $jwe->extract($segments[1], 'as_binary');
65 | $jwe->iv = $jwe->extract($segments[2], 'as_binary');
66 | $jwe->cipher_text = $jwe->extract($segments[3], 'as_binary');
67 | $jwe->authentication_tag = $jwe->extract($segments[4], 'as_binary');
68 | return $jwe;
69 | default:
70 | throw new JOSE_Exception_InvalidFormat('JWT should have exact 3 or 5 segments');
71 | }
72 | }
73 |
74 | protected function compact($segment) {
75 | if (is_object($segment)) {
76 | $stringified = str_replace("\/", "/", json_encode($segment));
77 | } else {
78 | $stringified = $segment;
79 | }
80 | if ($stringified === 'null' && $segment !== null) { // shouldn't happen, just for safe
81 | throw new JOSE_Exception_InvalidFormat('Compact seriarization failed');
82 | }
83 | return JOSE_URLSafeBase64::encode($stringified);
84 | }
85 |
86 | protected function extract($segment, $as_binary = false) {
87 | $stringified = JOSE_URLSafeBase64::decode($segment);
88 | if ($as_binary) {
89 | $extracted = $stringified;
90 | } else {
91 | $extracted = json_decode($stringified);
92 | if ($stringified !== 'null' && $extracted === null) {
93 | throw new JOSE_Exception_InvalidFormat('Compact de-serialization failed');
94 | }
95 | }
96 | return $extracted;
97 | }
98 |
99 | private function toJWS() {
100 | return new JOSE_JWS($this);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/JOSE/URLSafeBase64.php:
--------------------------------------------------------------------------------
1 | plain_text = 'Hello World';
12 | }
13 |
14 | function testToString() {
15 | $jwe = new JOSE_JWE($this->plain_text);
16 | $jwe->encrypt($this->rsa_keys['public']);
17 | $segments = explode('.', $jwe->toString());
18 | $this->assertEquals(5, count($segments));
19 | }
20 |
21 | function test__toString() {
22 | $jwe = new JOSE_JWE($this->plain_text);
23 | $jwe->encrypt($this->rsa_keys['public']);
24 | $segments = explode('.', sprintf('%s', $jwe));
25 | $this->assertEquals(5, count($segments));
26 | }
27 |
28 | function testEncryptRSA15_A128CBCHS256() {
29 | $jwe = new JOSE_JWE($this->plain_text);
30 | $jwe->encrypt($this->rsa_keys['public']);
31 | $jwe_decoded = JOSE_JWT::decode($jwe->toString());
32 | $this->assertEquals($this->plain_text, $jwe_decoded->decrypt($this->rsa_keys['private'])->plain_text);
33 | }
34 |
35 | function testEncryptRSA15_A256CBCHS512() {
36 | $jwe = new JOSE_JWE($this->plain_text);
37 | $jwe->encrypt($this->rsa_keys['public'], 'RSA1_5', 'A256CBC-HS512');
38 | $jwe_decoded = JOSE_JWT::decode($jwe->toString());
39 | $this->assertEquals($this->plain_text, $jwe_decoded->decrypt($this->rsa_keys['private'])->plain_text);
40 | }
41 |
42 | function testEncryptRSA15_A128GCM() {
43 | $jwe = new JOSE_JWE($this->plain_text);
44 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
45 | $jwe->encrypt($this->rsa_keys['public'], 'RSA1_5', 'A128GCM');
46 | }
47 |
48 | function testEncryptRSA15_A256GCM() {
49 | $jwe = new JOSE_JWE($this->plain_text);
50 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
51 | $jwe->encrypt($this->rsa_keys['public'], 'RSA1_5', 'A256GCM');
52 | }
53 |
54 | function testEncryptRSAOAEP_A128CBCHS256() {
55 | $jwe = new JOSE_JWE($this->plain_text);
56 | $jwe->encrypt($this->rsa_keys['public'], 'RSA-OAEP');
57 | $jwe_decoded = JOSE_JWT::decode($jwe->toString());
58 | $this->assertEquals($this->plain_text, $jwe_decoded->decrypt($this->rsa_keys['private'])->plain_text);
59 | }
60 |
61 | function testEncryptRSAOAEP_A256CBCHS512() {
62 | $jwe = new JOSE_JWE($this->plain_text);
63 | $jwe->encrypt($this->rsa_keys['public'], 'RSA-OAEP', 'A256CBC-HS512');
64 | $jwe_decoded = JOSE_JWT::decode($jwe->toString());
65 | $this->assertEquals($this->plain_text, $jwe_decoded->decrypt($this->rsa_keys['private'])->plain_text);
66 | }
67 |
68 | function testEncryptDir_A128CBCHS256() {
69 | $secret = Random::string(256 / 8);
70 | $jwe = new JOSE_JWE($this->plain_text);
71 | $jwe = $jwe->encrypt($secret, 'dir');
72 | $jwe_decoded = JOSE_JWT::decode($jwe->toString());
73 | $this->assertEquals($this->plain_text, $jwe_decoded->decrypt($secret)->plain_text);
74 | }
75 |
76 | function testEncryptA128KW_A128CBCHS256() {
77 | $jwe = new JOSE_JWE($this->plain_text);
78 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
79 | $jwe->encrypt($this->rsa_keys['public'], 'A128KW');
80 | }
81 |
82 | function testEncryptRSA15_Unknown() {
83 | $jwe = new JOSE_JWE($this->plain_text);
84 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
85 | $jwe->encrypt($this->rsa_keys['public'], 'RSA1_5', 'Unknown');
86 | }
87 |
88 | function testEncryptUnknown_A128CBCHS256() {
89 | $jwe = new JOSE_JWE($this->plain_text);
90 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
91 | $jwe->encrypt($this->rsa_keys['public'], 'Unknown');
92 | }
93 |
94 | function testDecryptRSA15_A128CBCHS256() {
95 | $input = 'eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.A2_4qS-61x17Q9NdT5kE0Qv5vw-D7zqGxACw42qM6l1iIHu31cENA8O5GTUhWordW3f93WY4ap1ZvCHO7pbbCF4NpOIMKjZtHObHRtPnA12zn-JZIxPCUHDtIQ6ucT-B0g5AmKDEDFO78Murz5l9QZH_Tl5t5x5-Asi3BO9Mm4s5dldykMvFxdC1j5IZ1ZBgN243OdKmvkTa0dn9wgjz9XEZHXoX_TKE4kDMyzIgW_U6Y4mP-cfZjQhTZAGwsBEz1kYTbM0bCf-FK3BBktpWZzjp4Y7cL6Zc7CabkNWAmMPcenxOFQZCOTeikmj4xrgZ9uPJ-DwJJNlnW_jPhEaesw.E1-sid2lZsrNOqc9vjgajg.s9vv7y5Qt5MwpA2AEGeuBQ.gH1oQlBSCdMK_jJEtoyWAw';
96 | $jwe = JOSE_JWE::decode($input);
97 | $jwe->decrypt($this->rsa_keys['private']);
98 | $this->assertEquals($this->plain_text, $jwe->plain_text);
99 | }
100 |
101 | function testDecode() {
102 | $input = 'eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.A2_4qS-61x17Q9NdT5kE0Qv5vw-D7zqGxACw42qM6l1iIHu31cENA8O5GTUhWordW3f93WY4ap1ZvCHO7pbbCF4NpOIMKjZtHObHRtPnA12zn-JZIxPCUHDtIQ6ucT-B0g5AmKDEDFO78Murz5l9QZH_Tl5t5x5-Asi3BO9Mm4s5dldykMvFxdC1j5IZ1ZBgN243OdKmvkTa0dn9wgjz9XEZHXoX_TKE4kDMyzIgW_U6Y4mP-cfZjQhTZAGwsBEz1kYTbM0bCf-FK3BBktpWZzjp4Y7cL6Zc7CabkNWAmMPcenxOFQZCOTeikmj4xrgZ9uPJ-DwJJNlnW_jPhEaesw.E1-sid2lZsrNOqc9vjgajg.s9vv7y5Qt5MwpA2AEGeuBQ.gH1oQlBSCdMK_jJEtoyWAw';
103 | $jwe = JOSE_JWE::decode($input);
104 | $this->assertNull($jwe->plain_text);
105 | $this->assertEquals(array(
106 | "alg" => "RSA1_5",
107 | "enc" => "A128CBC-HS256"
108 | ), $jwe->header);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/test/JOSE/JWKSet_Test.php:
--------------------------------------------------------------------------------
1 | 'RSA',
7 | 'e' => 'AQAB',
8 | 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYcz...'
9 | ));
10 | $jwks = new JOSE_JWKSet($key);
11 | $this->assertEquals('{"keys":[{"kty":"RSA","e":"AQAB","n":"x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYcz...","kid":"Nxz0OiuV92r008w3aI60jWb9tCuT0SixwtyllpaIzW0"}]}', $jwks->toString());
12 | }
13 |
14 | function testArrayInput() {
15 | $key = array(
16 | 'kty' => 'RSA',
17 | 'e' => 'AQAB',
18 | 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYcz...'
19 | );
20 | $jwks = new JOSE_JWKSet($key);
21 | $this->assertEquals('{"keys":[{"kty":"RSA","e":"AQAB","n":"x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYcz..."}]}', $jwks->toString());
22 | }
23 |
24 | function test__toString() {
25 | $key = array(
26 | 'kty' => 'RSA',
27 | 'e' => 'AQAB',
28 | 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYcz...'
29 | );
30 | $jwks = new JOSE_JWKSet($key);
31 | $this->assertEquals('{"keys":[{"kty":"RSA","e":"AQAB","n":"x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYcz..."}]}', sprintf('%s', $jwks));
32 | }
33 | }
--------------------------------------------------------------------------------
/test/JOSE/JWK_Test.php:
--------------------------------------------------------------------------------
1 | setExpectedException('JOSE_Exception_InvalidFormat');
9 | new JOSE_JWK(array('n' => 'n'));
10 | }
11 |
12 | function testToString() {
13 | $jwk = new JOSE_JWK(array('kty' => 'RSA', 'e' => 'e', 'n' => 'n'));
14 | $this->assertEquals('{"kty":"RSA","e":"e","n":"n","kid":"lPd1Hx7fpYY23pQVKnFvOEtk_jFe5EV8ZISUGTSGA_U"}', $jwk->toString());
15 | }
16 |
17 | function test__toString() {
18 | $jwk = new JOSE_JWK(array('kty' => 'RSA', 'e' => 'e', 'n' => 'n'));
19 | $this->assertEquals('{"kty":"RSA","e":"e","n":"n","kid":"lPd1Hx7fpYY23pQVKnFvOEtk_jFe5EV8ZISUGTSGA_U"}', sprintf('%s', $jwk));
20 | }
21 |
22 | function testEncodeRSAPublicKey() {
23 | $rsa = new RSA();
24 | $rsa->loadKey($this->rsa_keys['public']);
25 | $jwk = JOSE_JWK::encode($rsa);
26 | $this->assertInstanceOf('JOSE_JWK', $jwk);
27 | $this->assertEquals('AQAB', $jwk->components['e']);
28 | $this->assertEquals('x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', $jwk->components['n']);
29 | $this->assertNotContains('d', $jwk->components);
30 | }
31 |
32 | function testEncodeRSAPrivateKey() {
33 | $rsa = new RSA();
34 | $rsa->loadKey($this->rsa_keys['private']);
35 | $jwk = JOSE_JWK::encode($rsa);
36 | $this->assertInstanceOf('JOSE_JWK', $jwk);
37 | $this->assertEquals('AQAB', $jwk->components['e']);
38 | $this->assertEquals('x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ', $jwk->components['n']);
39 | $this->assertEquals('S3xQjvVh-PJv9tK_gHeJB0nWBx6bewWdakI7Pm9nR30ZNKYtQc15eoESczhjsPe3z_DGJebohZmmx4bzNlQSFBzj4W1TFXFM05oqSi7DfV1jZyzlNSYKsjT0P4gBoziNwc9uDLPWNUFPo_6gF7rJo2r1chix-Oftpt2Sc0SsdyEESBMR5REMccX5gZIhN-DUTN4gt9GNeDRy9h-gNFxgNNtt17HzEg52gbl3UnEuuPXE2wcctE1nxT3WDdtVqb6nbaNfxLiaAWaL2uYBvU2_AvKu1b7VEPmP9pTEMyriVzh4Jb2ZtIUpna518M044GPKs1TgMHSAxpOaQvnpar9lrQ', $jwk->components['d']);
40 | }
41 |
42 | function testEncodeWithExtraComponents() {
43 | $rsa = new RSA();
44 | $rsa->loadKey($this->rsa_keys['private']);
45 | $jwk = JOSE_JWK::encode($rsa, array(
46 | 'kid' => '12345',
47 | 'use' => 'sig'
48 | ));
49 | $this->assertEquals('12345', $jwk->components['kid']);
50 | $this->assertEquals('sig', $jwk->components['use']);
51 | }
52 |
53 | function testEncodeWithUnexpectedAlg() {
54 | $key = new RC2();
55 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
56 | JOSE_JWK::encode($key);
57 | }
58 |
59 | function testDecodeRSAPublicKey() {
60 | $components = array(
61 | 'kty' => 'RSA',
62 | 'e' => 'AQAB',
63 | 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ'
64 | );
65 | $key = JOSE_JWK::decode($components);
66 | $this->assertInstanceOf('phpseclib\Crypt\RSA', $key);
67 | $this->assertEquals(
68 | preg_replace("/\r\n|\r|\n/", '', $this->rsa_keys['public']),
69 | preg_replace("/\r\n|\r|\n/", '', $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1_RAW))
70 | );
71 | }
72 |
73 | function testDecodeRSAPrivateKey() {
74 | $components = array(
75 | 'kty' => 'RSA',
76 | 'e' => 'AQAB',
77 | 'n' => 'x9vNhcvSrxjsegZAAo4OEuoZOV_oxINEeWneJYczS80_bQ1J6lSSJ81qecxXAzCLPlvsFoP4eeUNXSt_G7hP7SAM479N-kY_MzbihJ5LRY9sRzLbQTMeqsmDAmmQe4y3Ke3bvd70r8VOmo5pqM3IPLGwBkTRTQmyRsDQArilg6WtxDUgy5ol2STHFA8E1iCReh9bck8ZaLxzVhYRXZ0nuOKWGRMppocPlp55HVohOItUZh7uSCchLcVAZuhTTNaDLtLIJ6G0yNJvfEieJUhA8wGBoPhD3LMQwQMxTMerpjZhP_qjm6GgeWpKf-iVil86_PSy_z0Vw06_rD0sfXPtlQ',
78 | 'd' => 'S3xQjvVh-PJv9tK_gHeJB0nWBx6bewWdakI7Pm9nR30ZNKYtQc15eoESczhjsPe3z_DGJebohZmmx4bzNlQSFBzj4W1TFXFM05oqSi7DfV1jZyzlNSYKsjT0P4gBoziNwc9uDLPWNUFPo_6gF7rJo2r1chix-Oftpt2Sc0SsdyEESBMR5REMccX5gZIhN-DUTN4gt9GNeDRy9h-gNFxgNNtt17HzEg52gbl3UnEuuPXE2wcctE1nxT3WDdtVqb6nbaNfxLiaAWaL2uYBvU2_AvKu1b7VEPmP9pTEMyriVzh4Jb2ZtIUpna518M044GPKs1TgMHSAxpOaQvnpar9lrQ'
79 | );
80 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
81 | JOSE_JWK::decode($components);
82 | }
83 |
84 | function testDecodeWithUnexpectedAlg() {
85 | $components = array(
86 | 'kty' => 'EC',
87 | 'crv' => 'crv',
88 | 'x' => 'x',
89 | 'y' => 'y'
90 | );
91 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
92 | JOSE_JWK::decode($components);
93 | }
94 |
95 | function testThumbprint() {
96 | $rsa = new RSA();
97 | $rsa->loadKey($this->rsa_keys['public']);
98 | $jwk = JOSE_JWK::encode($rsa);
99 | $this->assertInstanceOf('JOSE_JWK', $jwk);
100 | $this->assertEquals('nuBTimkcSt_AuEsD8Yv3l8CoGV31bu_3gsRDGN1iVKA', $jwk->thumbprint());
101 | $this->assertEquals('nuBTimkcSt_AuEsD8Yv3l8CoGV31bu_3gsRDGN1iVKA', $jwk->thumbprint('sha256'));
102 | $this->assertEquals('6v7pXTnQLMiQgvJlPJUdhAUSuGLzgF8C1r3ABAMFet6bc53ea-Pq4ZGbGu3RoAFsNRT1-RhTzDqtqXuLU6NOtw', $jwk->thumbprint('sha512'));
103 | }
104 |
105 | }
--------------------------------------------------------------------------------
/test/JOSE/JWS_Test.php:
--------------------------------------------------------------------------------
1 | plain_jwt = new JOSE_JWT(array(
13 | 'foo' => 'bar'
14 | ));
15 | }
16 |
17 | function testToJSON() {
18 | $expected = '{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9","payload":"eyJmb28iOiJiYXIifQ","signature":"GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw"}';
19 | $jws = new JOSE_JWS($this->plain_jwt);
20 | $jws = $jws->sign($this->rsa_keys['private'], 'RS256');
21 | $this->assertEquals($expected, sprintf('%s', $jws->toJSON()));
22 | }
23 |
24 | function testToJSONWithGeneralSyntax() {
25 | $expected = '{"payload":"eyJmb28iOiJiYXIifQ","signatures":{"protected":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9","signature":"GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw"}}';
26 | $jws = new JOSE_JWS($this->plain_jwt);
27 | $jws = $jws->sign($this->rsa_keys['private'], 'RS256');
28 | $this->assertEquals($expected, sprintf('%s', $jws->toJSON('general-syntax')));
29 | }
30 |
31 | function testSignHS256() {
32 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw';
33 | $jws = new JOSE_JWS($this->plain_jwt);
34 | $jws = $jws->sign('shared-secret', 'HS256');
35 | $this->assertEquals($expected, $jws->toString());
36 | }
37 |
38 | function testSignHS384() {
39 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJmb28iOiJiYXIifQ.EoHJwaBtAB7OQzhInUDK5QBrKqhYX8OodiAgusI3fOJsueTm6aOpKvngGj3afGQo';
40 | $jws = new JOSE_JWS($this->plain_jwt);
41 | $jws = $jws->sign('shared-secret', 'HS384');
42 | $this->assertEquals($expected, $jws->toString());
43 | }
44 |
45 | function testSignHS512() {
46 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJmb28iOiJiYXIifQ.eLwaujbDB1c19eOGpxwMksVHCkE5XLA4eps80ZDPAE8_FdQOMQvC6lF0mtAHljAai9XHEDWMXUz1NCeovs8ZVQ';
47 | $jws = new JOSE_JWS($this->plain_jwt);
48 | $jws = $jws->sign('shared-secret', 'HS512');
49 | $this->assertEquals($expected, $jws->toString());
50 | }
51 |
52 | function testSignRS256() {
53 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw';
54 | $jws = new JOSE_JWS($this->plain_jwt);
55 | $jws = $jws->sign($this->rsa_keys['private'], 'RS256');
56 | $this->assertEquals($expected, $jws->toString());
57 | }
58 |
59 | function testSignRS384() {
60 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJmb28iOiJiYXIifQ.Odg4nlRTnH1mI1JQEJEQCB1mmqDPFn-Gf5Te8IfLzu7sGDrvZdvGe6HutsDO3mXi7FLtQcI2i0KEQxj8fDUV4vfR1fbfyGQaz02qnt3HKEOgRGwFH1l57ayGChZftXhSCpbt9sMwTg1lsZ_egThQWG0ZErkibmXIt5ZxNwITaXX4oU3k12eH492IsScz_tIaf9NCwIQlAPodiVQL7WMQgej0o4LuZKk6ZgBsDJz_Ms2_iONxzGPWOT76iLOwYT8QaEsLX6d8_WsZ4wnfaxHVlg-zNM0Lhisi_F0_tFeueDOZPJnQp_InV7iYzP4adWOItzG_Qz_-EaNGTz4RJtxqAQ';
61 | $jws = new JOSE_JWS($this->plain_jwt);
62 | $jws = $jws->sign($this->rsa_keys['private'], 'RS384');
63 | $this->assertEquals($expected, $jws->toString());
64 | }
65 |
66 | function testSignRS512() {
67 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJmb28iOiJiYXIifQ.uQAVgGt1oy8FlMaAx8UDnVwzuDuJsqYIDHm8cKRKqLqcZ0zUmQHgfonBA09r5CiqG5EGTaX58G6_hAFAmf-aRtJrm_cN-68xrliMXVH3m6vZdRKhbtYqCozjbmEH8nPwBFtlri15vhR5lWTT_x3VsZOHhuhbAFzyshIcYAxNDVkUssPWpDag26fRcPsIJ-Oozvp9ld1uOnu9BNSOCWF4DXUTRBfUx55pl1ihwgHrFt36eHdtQ90vJXflsJvLoHuKf4LKt0dOpsPYeJp74V1X06DFlVqL9JGAS3iSLZ_tK_MpZheJqIr5iPl4qWc4k6gSbeomXR1opKqWmbje5JiZmw';
68 | $jws = new JOSE_JWS($this->plain_jwt);
69 | $jws = $jws->sign($this->rsa_keys['private'], 'RS512');
70 | $this->assertEquals($expected, $jws->toString());
71 | }
72 |
73 | function testSignPS256() {
74 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJmb28iOiJiYXIifQ.x5S_So_vmBcuROQ1uqlZTCc5YWk9xMR4SyCrVwxylgewFVK-WIsiDyMvSuBeojNXk693f775HeO1h8VJIkuXN3wupPKn2OHFPvQMPdcygLxM7aGV8gG9Ocv-HHWAK_i3UQpek-2CjEDSGFBUQqvKKxqx7NrbB-xt4dBn6JeMEs5wqpADUDQWr5zC33OEwamZktPF10FS2HVRtLuS4X9J53x2kLIFxxqPq_pyvUvlfehniyzupyVMbhHPe9-kiibLVSN0dVX9w0UyNoNQ1ZxWXfMZ3gVsWIeaaXCseW8TD7Pm_7I6Y8_sALje08USJ4Sdj4ExpvJqqrnY2cCHIAGAQA';
75 | $jws = new JOSE_JWS($this->plain_jwt);
76 | $jws = $jws->sign($this->rsa_keys['private'], 'PS256');
77 | # NOTE: RSA-PSS generates different signature each time
78 | $expected_segments = explode('.', $expected);
79 | $given_segments = explode('.', $jws->toString());
80 | $this->assertEquals($expected_segments[0], $given_segments[0]);
81 | $this->assertEquals($expected_segments[1], $given_segments[1]);
82 | }
83 |
84 | function testSignPS384() {
85 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzM4NCJ9.eyJmb28iOiJiYXIifQ.vvJPhzH_aZiiFaaAPOfshgaRmiqRSmyUmvL02uZGyWNtjJuA_zEJsuvs18JzOkDgHCG5MsrfhWkJKsl9Pm2DLWo2D7b8NBKpHE1oedTptOOnk8wGWUU2vBXYmuoWcKzDrH0Bl697NTTNv72AeoMWzaOXqYTx_qcOZxlscGINm0-lqttSk-gnzqbOxSAacv_YeibofxvFNw3Q3eaP36f1glYOWHOQSSWoqe0cW0F8hxcLeEr4FPRwAaFnOfG0wDsYZ8huvEun4uopEitJugC8oYiE-iax-QbbwboIiYeZtDBG51uydkOEjKi3WexFjayiQSCgj_343mUdq1wzV9dt2w';
86 | $jws = new JOSE_JWS($this->plain_jwt);
87 | $jws = $jws->sign($this->rsa_keys['private'], 'PS384');
88 | # NOTE: RSA-PSS generates different signature each time
89 | $expected_segments = explode('.', $expected);
90 | $given_segments = explode('.', $jws->toString());
91 | $this->assertEquals($expected_segments[0], $given_segments[0]);
92 | $this->assertEquals($expected_segments[1], $given_segments[1]);
93 | }
94 |
95 | function testSignPS512() {
96 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJmb28iOiJiYXIifQ.g8x8IDQuG6-TMHowGvtFSurHrxccbP9ihmRIrwtccYxO1tkBSoU1Sgl8Cf5fj4u2E24vIQIc6feaTHIt--T2gdxvvSf2W0dhfP7GH4bajiOuL7lz2QcjypvxXdhoZM3PAGyWLYK76ZJ2RCalEvApZrWGsBud-h8Gnvd69wotm6hay8ZIbm7KEy0uuRnLF9r95uKxhMH5HVWQiPi4sw3FJgUlrBL4PeLTiRbrmVmCxuD-VTAZnxUZQkyrSwF0i4YPx9erptGQY6tndB6f_7oM8aDmj4xp3EjWIhOmJ4PfIZhBTeNpQW9eKto9Q2St_rruMlhrrFdaB7w8240pMKFkqw';
97 | $jws = new JOSE_JWS($this->plain_jwt);
98 | $jws = $jws->sign($this->rsa_keys['private'], 'PS512');
99 | # NOTE: RSA-PSS generates different signature each time
100 | $expected_segments = explode('.', $expected);
101 | $given_segments = explode('.', $jws->toString());
102 | $this->assertEquals($expected_segments[0], $given_segments[0]);
103 | $this->assertEquals($expected_segments[1], $given_segments[1]);
104 | }
105 |
106 | function testSignRS256WithInvalidPrivateKey() {
107 | $jws = new JOSE_JWS($this->plain_jwt);
108 | $this->setExpectedException('JOSE_Exception');
109 | $jws = $jws->sign('invalid pem', 'RS256');
110 | }
111 |
112 | function testSignES256() {
113 | $jws = new JOSE_JWS($this->plain_jwt);
114 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
115 | $jws = $jws->sign('es key should be here', 'ES256');
116 | }
117 |
118 | function testSignWithCryptRSA() {
119 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw';
120 | $key = new RSA();
121 | $key->loadKey($this->rsa_keys['private']);
122 | $jws = new JOSE_JWS($this->plain_jwt);
123 | $jws = $jws->sign($key, 'RS256');
124 | $this->assertEquals($expected, $jws->toString());
125 | }
126 |
127 | function testSignWithJWK() {
128 | $key = new RSA();
129 | $key->loadKey($this->rsa_keys['private']);
130 | $jwk = JOSE_JWK::encode($key);
131 | $jws = new JOSE_JWS($this->plain_jwt);
132 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
133 | $jws->sign($jwk, 'RS256');
134 | }
135 |
136 | function testSignUnknowAlg() {
137 | $jws = new JOSE_JWS($this->plain_jwt);
138 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
139 | $jws = $jws->sign('secret', 'AES256');
140 | }
141 |
142 | function testVerifyHS256() {
143 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw';
144 | $jwt = JOSE_JWT::decode($input);
145 | $jws = new JOSE_JWS($jwt);
146 | $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS256'));
147 | }
148 |
149 | function testVerifyHS256_without_explicit_alg() {
150 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.jBKXM6zRu0nP2tYgNTgFxRDwKoiEbNl1P6GyXEHIwEw';
151 | $jwt = JOSE_JWT::decode($input);
152 | $jws = new JOSE_JWS($jwt);
153 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
154 | $jws->verify('shared-secret');
155 | }
156 |
157 | function testVerifyHS384() {
158 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJmb28iOiJiYXIifQ.EoHJwaBtAB7OQzhInUDK5QBrKqhYX8OodiAgusI3fOJsueTm6aOpKvngGj3afGQo';
159 | $jwt = JOSE_JWT::decode($input);
160 | $jws = new JOSE_JWS($jwt);
161 | $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS384'));
162 | }
163 |
164 | function testVerifyHS512() {
165 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJmb28iOiJiYXIifQ.eLwaujbDB1c19eOGpxwMksVHCkE5XLA4eps80ZDPAE8_FdQOMQvC6lF0mtAHljAai9XHEDWMXUz1NCeovs8ZVQ';
166 | $jwt = JOSE_JWT::decode($input);
167 | $jws = new JOSE_JWS($jwt);
168 | $this->assertInstanceOf('JOSE_JWS', $jws->verify('shared-secret', 'HS512'));
169 | }
170 |
171 | function testVerifyRS256() {
172 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw';
173 | $jwt = JOSE_JWT::decode($input);
174 | $jws = new JOSE_JWS($jwt);
175 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public']));
176 | }
177 |
178 | function testVerifyRS384() {
179 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJmb28iOiJiYXIifQ.Odg4nlRTnH1mI1JQEJEQCB1mmqDPFn-Gf5Te8IfLzu7sGDrvZdvGe6HutsDO3mXi7FLtQcI2i0KEQxj8fDUV4vfR1fbfyGQaz02qnt3HKEOgRGwFH1l57ayGChZftXhSCpbt9sMwTg1lsZ_egThQWG0ZErkibmXIt5ZxNwITaXX4oU3k12eH492IsScz_tIaf9NCwIQlAPodiVQL7WMQgej0o4LuZKk6ZgBsDJz_Ms2_iONxzGPWOT76iLOwYT8QaEsLX6d8_WsZ4wnfaxHVlg-zNM0Lhisi_F0_tFeueDOZPJnQp_InV7iYzP4adWOItzG_Qz_-EaNGTz4RJtxqAQ';
180 | $jwt = JOSE_JWT::decode($input);
181 | $jws = new JOSE_JWS($jwt);
182 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public']));
183 | }
184 |
185 | function testVerifyRS512() {
186 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJmb28iOiJiYXIifQ.uQAVgGt1oy8FlMaAx8UDnVwzuDuJsqYIDHm8cKRKqLqcZ0zUmQHgfonBA09r5CiqG5EGTaX58G6_hAFAmf-aRtJrm_cN-68xrliMXVH3m6vZdRKhbtYqCozjbmEH8nPwBFtlri15vhR5lWTT_x3VsZOHhuhbAFzyshIcYAxNDVkUssPWpDag26fRcPsIJ-Oozvp9ld1uOnu9BNSOCWF4DXUTRBfUx55pl1ihwgHrFt36eHdtQ90vJXflsJvLoHuKf4LKt0dOpsPYeJp74V1X06DFlVqL9JGAS3iSLZ_tK_MpZheJqIr5iPl4qWc4k6gSbeomXR1opKqWmbje5JiZmw';
187 | $jwt = JOSE_JWT::decode($input);
188 | $jws = new JOSE_JWS($jwt);
189 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public']));
190 | }
191 |
192 | function testVerifyPS256() {
193 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzI1NiJ9.eyJmb28iOiJiYXIifQ.x5S_So_vmBcuROQ1uqlZTCc5YWk9xMR4SyCrVwxylgewFVK-WIsiDyMvSuBeojNXk693f775HeO1h8VJIkuXN3wupPKn2OHFPvQMPdcygLxM7aGV8gG9Ocv-HHWAK_i3UQpek-2CjEDSGFBUQqvKKxqx7NrbB-xt4dBn6JeMEs5wqpADUDQWr5zC33OEwamZktPF10FS2HVRtLuS4X9J53x2kLIFxxqPq_pyvUvlfehniyzupyVMbhHPe9-kiibLVSN0dVX9w0UyNoNQ1ZxWXfMZ3gVsWIeaaXCseW8TD7Pm_7I6Y8_sALje08USJ4Sdj4ExpvJqqrnY2cCHIAGAQA';
194 | $jwt = JOSE_JWT::decode($input);
195 | $jws = new JOSE_JWS($jwt);
196 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public']));
197 | }
198 |
199 | function testVerifyPS384() {
200 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzM4NCJ9.eyJmb28iOiJiYXIifQ.vvJPhzH_aZiiFaaAPOfshgaRmiqRSmyUmvL02uZGyWNtjJuA_zEJsuvs18JzOkDgHCG5MsrfhWkJKsl9Pm2DLWo2D7b8NBKpHE1oedTptOOnk8wGWUU2vBXYmuoWcKzDrH0Bl697NTTNv72AeoMWzaOXqYTx_qcOZxlscGINm0-lqttSk-gnzqbOxSAacv_YeibofxvFNw3Q3eaP36f1glYOWHOQSSWoqe0cW0F8hxcLeEr4FPRwAaFnOfG0wDsYZ8huvEun4uopEitJugC8oYiE-iax-QbbwboIiYeZtDBG51uydkOEjKi3WexFjayiQSCgj_343mUdq1wzV9dt2w';
201 | $jwt = JOSE_JWT::decode($input);
202 | $jws = new JOSE_JWS($jwt);
203 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public']));
204 | }
205 |
206 | function testVerifyPS512() {
207 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJQUzUxMiJ9.eyJmb28iOiJiYXIifQ.g8x8IDQuG6-TMHowGvtFSurHrxccbP9ihmRIrwtccYxO1tkBSoU1Sgl8Cf5fj4u2E24vIQIc6feaTHIt--T2gdxvvSf2W0dhfP7GH4bajiOuL7lz2QcjypvxXdhoZM3PAGyWLYK76ZJ2RCalEvApZrWGsBud-h8Gnvd69wotm6hay8ZIbm7KEy0uuRnLF9r95uKxhMH5HVWQiPi4sw3FJgUlrBL4PeLTiRbrmVmCxuD-VTAZnxUZQkyrSwF0i4YPx9erptGQY6tndB6f_7oM8aDmj4xp3EjWIhOmJ4PfIZhBTeNpQW9eKto9Q2St_rruMlhrrFdaB7w8240pMKFkqw';
208 | $jwt = JOSE_JWT::decode($input);
209 | $jws = new JOSE_JWS($jwt);
210 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($this->rsa_keys['public']));
211 | }
212 |
213 | function testVerifyES256() {
214 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.MEQCIDh9M3Id8pPd9fp6kgtirYpAirRCU-H0IbaeruLOYWc_AiBhbsswHCIlY5yqWDsOU_sy3lMnyXlrYoQLcejPxL-nDg';
215 | $jwt = JOSE_JWT::decode($input);
216 | $jws = new JOSE_JWS($jwt);
217 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
218 | $jws = $jws->verify('es key should be here');
219 | }
220 |
221 | function testVerifyUnknowAlg() {
222 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJ1bmtub3duIn0.eyJmb28iOiJiYXIifQ.';
223 | $jwt = JOSE_JWT::decode($input);
224 | $jws = new JOSE_JWS($jwt);
225 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
226 | $jws = $jws->verify('no key works');
227 | }
228 |
229 | function testVerifyWithCryptRSA() {
230 | $key = new RSA();
231 | $key->loadKey($this->rsa_keys['public']);
232 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw';
233 | $jwt = JOSE_JWT::decode($input);
234 | $jws = new JOSE_JWS($jwt);
235 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($key));
236 | }
237 |
238 | function testVerifyWithJWK() {
239 | $key = new RSA();
240 | $key->loadKey($this->rsa_keys['public']);
241 | $jwk = JOSE_JWK::encode($key);
242 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.GzzxRgDHjgBjDkbMsKaFhWnQ43xKlh8T7Ce34b9ye4afuIfE2EglIlK1itGRx1PtH7UOcwtXVWElJ0lHuuTl6hCUL5SDOMJxiPfr5SkTZFWy2SlSYNtdRfra6NPeEa3-a_15dUYv41QY14TCl5HaP7jeMLeqcTlMcjra9fDPMWUciSyWay6025wUiSQBmWW-19GNZQnRHxXNX3lCVMEQMASYT-6QqBvoiJ6vezIt08RghgGdMH1iGY_Gnb7ISuA-lvKk6fcQvQ3MN5Cx0CeqXlXP8NQQF0OwkUgTjNGsKmCG6jKlLZLeXJb72KVK1yR-6jp7OQqqzrovIP7lp-FwIw';
243 | $jwt = JOSE_JWT::decode($input);
244 | $jws = new JOSE_JWS($jwt);
245 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($jwk));
246 | }
247 |
248 | function testVerifyWithGoogleIDToken() {
249 | $id_token_string = file_get_contents($this->fixture_dir . 'google.jwt');
250 | $cert_string = file_get_contents($this->fixture_dir . 'google.crt');
251 | $x509 = new X509();
252 | $x509->loadX509($cert_string);
253 | $public_key = $x509->getPublicKey()->getPublicKey();
254 | $jwt = JOSE_JWT::decode($id_token_string);
255 | $jws = new JOSE_JWS($jwt);
256 | $this->assertInstanceOf('JOSE_JWS', $jws->verify($public_key));
257 | }
258 |
259 | function testVerifyMalformedJWS_HS256_to_none() {
260 | $malformed_jwt = JOSE_JWT::decode($this->plain_jwt->toString());
261 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
262 | $malformed_jwt->verify('secret');
263 | }
264 |
265 | function testVerifyMalformedJWS_RS256_to_HS256_without_explicit_alg() {
266 | $malformed_jwt = JOSE_JWT::decode(
267 | $this->plain_jwt->sign($this->rsa_keys['public'], 'HS256')->toString()
268 | );
269 | $this->setExpectedException('JOSE_Exception_UnexpectedAlgorithm');
270 | $malformed_jwt->verify($this->rsa_keys['public']);
271 | }
272 |
273 | function testVerifyMalformedJWS_RS256_to_HS256_with_explicit_alg() {
274 | $malformed_jwt = JOSE_JWT::decode(
275 | $this->plain_jwt->sign($this->rsa_keys['public'], 'HS256')->toString()
276 | );
277 | $this->setExpectedException('PHPUnit_Framework_Error_Notice', 'Invalid signature');
278 | $malformed_jwt->verify($this->rsa_keys['public'], 'RS256');
279 | }
280 | }
--------------------------------------------------------------------------------
/test/JOSE/JWT_Test.php:
--------------------------------------------------------------------------------
1 | '[]'
8 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.e30.';
9 | $jwt = new JOSE_JWT();
10 | $this->assertEquals($expected, $jwt->toString());
11 | }
12 |
13 | function testToStringWithConnectClaims() {
14 | # NOTE:
15 | # PHP converts '/' to '\/' in JSON, it can be different in other languages.
16 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJncmVlLXVpZC0xMjM0NSIsImlzcyI6Imh0dHBzOi8vZ3JlZS5uZXQiLCJhdWQiOiJncmVlLWFwcGlkLTEyMzQ1In0.';
17 | $jwt = new JOSE_JWT(array(
18 | 'sub' => 'gree-uid-12345',
19 | 'iss' => 'https://gree.net',
20 | 'aud' => 'gree-appid-12345'
21 | ));
22 | $this->assertEquals($expected, $jwt->toString());
23 | }
24 |
25 | function test__toString() {
26 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJncmVlLXVpZC0xMjM0NSIsImlzcyI6Imh0dHBzOi8vZ3JlZS5uZXQiLCJhdWQiOiJncmVlLWFwcGlkLTEyMzQ1In0.';
27 | $jwt = new JOSE_JWT(array(
28 | 'sub' => 'gree-uid-12345',
29 | 'iss' => 'https://gree.net',
30 | 'aud' => 'gree-appid-12345'
31 | ));
32 | $this->assertEquals($expected, sprintf('%s', $jwt));
33 | }
34 |
35 | function testEncode() {
36 | $expected = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJncmVlLXVpZC0xMjM0NSIsImlzcyI6Imh0dHBzOi8vZ3JlZS5uZXQiLCJhdWQiOiJncmVlLWFwcGlkLTEyMzQ1In0.';
37 | $jwt = JOSE_JWT::encode(array(
38 | 'sub' => 'gree-uid-12345',
39 | 'iss' => 'https://gree.net',
40 | 'aud' => 'gree-appid-12345'
41 | ));
42 | $this->assertEquals($expected, $jwt->toString());
43 | }
44 |
45 | function testDecode() {
46 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwiZm9vIjoiZm9vIn0.eyJzdWIiOiJncmVlLXVpZC0xMjM0NSIsImlzcyI6Imh0dHBzOlwvXC9ncmVlLm5ldCIsImF1ZCI6ImdyZWUtYXBwaWQtMTIzNDUifQ.';
47 | $expected = array(
48 | 'header' => array(
49 | 'typ' => 'JWT',
50 | 'alg' => 'none',
51 | 'foo' => 'foo'
52 | ),
53 | 'claims' => array(
54 | 'sub' => 'gree-uid-12345',
55 | 'iss' => 'https://gree.net',
56 | 'aud' => 'gree-appid-12345'
57 | )
58 | );
59 | $jwt = JOSE_JWT::decode($input);
60 | $this->assertEquals($expected['header'], (array) $jwt->header);
61 | $this->assertEquals($expected['claims'], (array) $jwt->claims);
62 | }
63 |
64 | function testDecodeWithTooManyDots() {
65 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwiZm9vIjoiZm9vIn0.eyJzdWIiOiJncmVlLXVpZC0xMjM0NSIsImlzcyI6Imh0dHBzOlwvXC9ncmVlLm5ldCIsImF1ZCI6ImdyZWUtYXBwaWQtMTIzNDUifQ..';
66 | $this->setExpectedException('JOSE_Exception_InvalidFormat');
67 | JOSE_JWT::decode($input);
68 | }
69 |
70 | function testDecodeWithTooFewDots() {
71 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIiwiZm9vIjoiZm9vIn0.eyJzdWIiOiJncmVlLXVpZC0xMjM0NSIsImlzcyI6Imh0dHBzOlwvXC9ncmVlLm5ldCIsImF1ZCI6ImdyZWUtYXBwaWQtMTIzNDUifQ';
72 | $this->setExpectedException('JOSE_Exception_InvalidFormat');
73 | JOSE_JWT::decode($input);
74 | }
75 |
76 | function testDecodeWithInvalidSerialization() {
77 | $input = 'header.payload.signature';
78 | $this->setExpectedException('JOSE_Exception_InvalidFormat');
79 | JOSE_JWT::decode($input);
80 | }
81 |
82 | function testSign() {
83 | $expected = array(
84 | 'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJmb28iOiJiYXIifQ.',
85 | 'jws' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.bVhBeMrW5g33Vi4FLSLn7aqcmAiupmmw-AY17YxCYLI'
86 | );
87 | $expected_with_signature = '';
88 | $jwt = new JOSE_JWT(array(
89 | 'foo' => 'bar'
90 | ));
91 | $jws = $jwt->sign('secret');
92 | $this->assertEquals($expected['jwt'], $jwt->toString()); // no signature for the original $jwt object
93 | $this->assertEquals($expected['jws'], $jws->toString());
94 | }
95 |
96 | function testVerify() {
97 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.bVhBeMrW5g33Vi4FLSLn7aqcmAiupmmw-AY17YxCYLI';
98 | $jwt = JOSE_JWT::decode($input);
99 | $this->assertInstanceOf('JOSE_JWS', $jwt->verify('secret', 'HS256'));
100 | }
101 |
102 | function testVerifyInvalid() {
103 | $input = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmb28iOiJiYXIifQ.bVhBeMrW5g33Vi4FLSLn7aqcmAiupmmw-AY17YxCYLI-invalid';
104 | $jwt = JOSE_JWT::decode($input);
105 | $this->setExpectedException('JOSE_Exception_VerificationFailed');
106 | $res = $jwt->verify('secret', 'HS256');
107 | }
108 |
109 | function testEncrypt() {
110 | $jwt = new JOSE_JWT(array(
111 | 'foo' => 'bar'
112 | ));
113 | $jwe = $jwt->encrypt($this->rsa_keys['public']);
114 | $this->assertInstanceOf('JOSE_JWT', $jwt);
115 | $this->assertInstanceOf('JOSE_JWE', $jwe);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/test/JOSE/TestCase.php:
--------------------------------------------------------------------------------
1 | fixture_dir = dirname(__FILE__) . '/../fixtures/';
9 | $this->rsa_keys = array(
10 | 'public' => file_get_contents($this->fixture_dir . 'public_key.pem'),
11 | 'private' => file_get_contents($this->fixture_dir . 'private_key.pem')
12 | );
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/bootstrap.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | .
5 |
6 |
7 |
8 |
9 | ../src
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------