Skip to content

Commit 935d681

Browse files
authored
Jwt split (#118)
* JWS/JWE Split THis PR adds a `split` method for both JWS and JWE objects. It allows to explode a JWS/JWE that contains several signatures/recipients into a list of JWS/JWE with only one signature/recipient. It can be useful in certain cases e.g. where the verification of each signature is required or if a JWE has to be computed at once, but sent separetly to recipients. * Apply fixes from StyleCI (#117) [ci skip] [skip ci]
1 parent 4917738 commit 935d681

File tree

4 files changed

+161
-0
lines changed

4 files changed

+161
-0
lines changed

src/Component/Encryption/JWE.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,4 +302,29 @@ public function hasSharedHeaderParameter(string $key): bool
302302
{
303303
return array_key_exists($key, $this->sharedHeader);
304304
}
305+
306+
/**
307+
* This method splits the JWE into a list of JWEs.
308+
* It is only useful when the JWE contains more than one recipient (JSON General Serialization).
309+
*
310+
* @return JWE[]
311+
*/
312+
public function split(): array
313+
{
314+
$result = [];
315+
foreach ($this->recipients as $recipient) {
316+
$result[] = self::create(
317+
$this->ciphertext,
318+
$this->iv,
319+
$this->tag,
320+
$this->aad,
321+
$this->sharedHeader,
322+
$this->sharedProtectedHeader,
323+
$this->encodedSharedProtectedHeader,
324+
[$recipient]
325+
);
326+
}
327+
328+
return $result;
329+
}
305330
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* The MIT License (MIT)
7+
*
8+
* Copyright (c) 2014-2018 Spomky-Labs
9+
*
10+
* This software may be modified and distributed under the terms
11+
* of the MIT license. See the LICENSE file for details.
12+
*/
13+
14+
namespace Jose\Component\Encryption\Tests;
15+
16+
use Jose\Component\Core\Converter\StandardConverter;
17+
use Jose\Component\Encryption\Serializer\JSONGeneralSerializer;
18+
19+
/**
20+
* @group JWE
21+
*/
22+
class JWESplitTest extends EncryptionTest
23+
{
24+
/**
25+
* @test
26+
*/
27+
public function aJweObjectWithMoreThanOneRecipientCanBeSplittedIntoSeveralJweObjects()
28+
{
29+
$input = '{"recipients":[{"encrypted_key":"dYOD28kab0Vvf4ODgxVAJXgHcSZICSOp8M51zjwj4w6Y5G4XJQsNNIBiqyvUUAOcpL7S7-cFe7Pio7gV_Q06WmCSa-vhW6me4bWrBf7cHwEQJdXihidAYWVajJIaKMXMvFRMV6iDlRr076DFthg2_AV0_tSiV6xSEIFqt1xnYPpmP91tc5WJDOGb-wqjw0-b-S1laS11QVbuP78dQ7Fa0zAVzzjHX-xvyM2wxj_otxr9clN1LnZMbeYSrRicJK5xodvWgkpIdkMHo4LvdhRRvzoKzlic89jFWPlnBq_V4n5trGuExtp_-dbHcGlihqc_wGgho9fLMK8JOArYLcMDNQ","header":{"alg":"RSA1_5","kid":"[email protected]"}},{"encrypted_key":"ExInT0io9BqBMYF6-maw5tZlgoZXThD1zWKsHixJuw_elY4gSSId_w","header":{"alg":"ECDH-ES+A256KW","kid":"[email protected]","epk":{"kty":"EC","crv":"P-384","x":"Uzdvk3pi5wKCRc1izp5_r0OjeqT-I68i8g2b8mva8diRhsE2xAn2DtMRb25Ma2CX","y":"VDrRyFJh-Kwd1EjAgmj5Eo-CTHAZ53MC7PjjpLioy3ylEjI1pOMbw91fzZ84pbfm"}}},{"encrypted_key":"a7CclAejo_7JSuPB8zeagxXRam8dwCfmkt9-WyTpS1E","header":{"alg":"A256GCMKW","kid":"18ec08e1-bfa9-4d95-b205-2b4dd1d4321d","tag":"59Nqh1LlYtVIhfD3pgRGvw","iv":"AvpeoPZ9Ncn9mkBn"}}],"unprotected":{"cty":"text/plain"},"protected":"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0","iv":"VgEIHY20EnzUtZFl2RpB1g","ciphertext":"ajm2Q-OpPXCr7-MHXicknb1lsxLdXxK_yLds0KuhJzfWK04SjdxQeSw2L9mu3a_k1C55kCQ_3xlkcVKC5yr__Is48VOoK0k63_QRM9tBURMFqLByJ8vOYQX0oJW4VUHJLmGhF-tVQWB7Kz8mr8zeE7txF0MSaP6ga7-siYxStR7_G07Thd1jh-zGT0wxM5g-VRORtq0K6AXpLlwEqRp7pkt2zRM0ZAXqSpe1O6FJ7FHLDyEFnD-zDIZukLpCbzhzMDLLw2-8I14FQrgi-iEuzHgIJFIJn2wh9Tj0cg_kOZy9BqMRZbmYXMY9YQjorZ_P_JYG3ARAIF3OjDNqpdYe-K_5Q5crGJSDNyij_ygEiItR5jssQVH2ofDQdLChtazE","tag":"BESYyFN7T09KY7i8zKs5_g"}';
30+
$serializer = new JSONGeneralSerializer(new StandardConverter());
31+
$jwe = $serializer->unserialize($input);
32+
$split = $jwe->split();
33+
34+
self::assertEquals(3, $jwe->countRecipients());
35+
self::assertEquals(3, count($split));
36+
37+
for ($i = 0; $i < $jwe->countRecipients(); $i++) {
38+
$recipient1 = $jwe->getRecipient($i);
39+
$tempJwe = $split[$i];
40+
self::assertEquals(1, $tempJwe->countRecipients());
41+
self::assertEquals($jwe->getAAD(), $tempJwe->getAAD());
42+
self::assertEquals($jwe->getCiphertext(), $tempJwe->getCiphertext());
43+
self::assertEquals($jwe->getEncodedSharedProtectedHeader(), $tempJwe->getEncodedSharedProtectedHeader());
44+
self::assertEquals($jwe->getSharedProtectedHeader(), $tempJwe->getSharedProtectedHeader());
45+
self::assertEquals($jwe->getSharedHeader(), $tempJwe->getSharedHeader());
46+
self::assertEquals($jwe->getIV(), $tempJwe->getIV());
47+
self::assertEquals($jwe->getTag(), $tempJwe->getTag());
48+
self::assertEquals($jwe->isEncrypted(), $tempJwe->isEncrypted());
49+
50+
$recipient2 = $tempJwe->getRecipient(0);
51+
self::assertEquals($recipient1->getHeader(), $recipient2->getHeader());
52+
self::assertEquals($recipient1->getEncryptedKey(), $recipient2->getEncryptedKey());
53+
}
54+
}
55+
}

src/Component/Signature/JWS.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,32 @@ public function countSignatures(): int
154154
{
155155
return count($this->signatures);
156156
}
157+
158+
/**
159+
* This method splits the JWS into a list of JWSs.
160+
* It is only useful when the JWS contains more than one signature (JSON General Serialization).
161+
*
162+
* @return JWS[]
163+
*/
164+
public function split(): array
165+
{
166+
$result = [];
167+
foreach ($this->signatures as $signature) {
168+
$jws = self::create(
169+
$this->payload,
170+
$this->encodedPayload,
171+
$this->isPayloadDetached
172+
);
173+
$jws = $jws->addSignature(
174+
$signature->getSignature(),
175+
$signature->getProtectedHeader(),
176+
$signature->getEncodedProtectedHeader(),
177+
$signature->getHeader()
178+
);
179+
180+
$result[] = $jws;
181+
}
182+
183+
return $result;
184+
}
157185
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* The MIT License (MIT)
7+
*
8+
* Copyright (c) 2014-2018 Spomky-Labs
9+
*
10+
* This software may be modified and distributed under the terms
11+
* of the MIT license. See the LICENSE file for details.
12+
*/
13+
14+
namespace Jose\Component\Signature\Tests;
15+
16+
use Jose\Component\Core\Converter\StandardConverter;
17+
use Jose\Component\Signature\JWS;
18+
use Jose\Component\Signature\Serializer\JSONGeneralSerializer;
19+
20+
/**
21+
* @group JWS
22+
*/
23+
class JWSSplitTest extends SignatureTest
24+
{
25+
/**
26+
* @test
27+
*/
28+
public function aJwsObjectWithMoreThanOneRecipientCanBeSplittedIntoSeveralJwsObjects()
29+
{
30+
$input = '{"payload":"SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdSBkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmUgeW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4","signatures":[{"protected":"eyJhbGciOiJSUzI1NiJ9","header":{"kid":"[email protected]"},"signature":"MIsjqtVlOpa71KE-Mss8_Nq2YH4FGhiocsqrgi5NvyG53uoimic1tcMdSg-qptrzZc7CG6Svw2Y13TDIqHzTUrL_lR2ZFcryNFiHkSw129EghGpwkpxaTn_THJTCglNbADko1MZBCdwzJxwqZc-1RlpO2HibUYyXSwO97BSe0_evZKdjvvKSgsIqjytKSeAMbhMBdMma622_BG5t4sdbuCHtFjp9iJmkio47AIwqkZV1aIZsv33uPUqBBCXbYoQJwt7mxPftHmNlGoOSMxR_3thmXTCm4US-xiNOyhbm8afKK64jU6_TPtQHiJeQJxz9G3Tx-083B745_AfYOnlC9w"},{"header":{"alg":"ES512","kid":"[email protected]"},"signature":"ARcVLnaJJaUWG8fG-8t5BREVAuTY8n8YHjwDO1muhcdCoFZFFjfISu0Cdkn9Ybdlmi54ho0x924DUz8sK7ZXkhc7AFM8ObLfTvNCrqcI3Jkl2U5IX3utNhODH6v7xgy1Qahsn0fyb4zSAkje8bAWz4vIfj5pCMYxxm4fgV3q7ZYhm5eD"},{"protected":"eyJhbGciOiJIUzI1NiIsImtpZCI6IjAxOGMwYWU1LTRkOWItNDcxYi1iZmQ2LWVlZjMxNGJjNzAzNyJ9","signature":"s0h6KThzkfBBBkLspW1h84VsJZFTsPPqMDA7g1Md7p0"}]}';
31+
$serializer = new JSONGeneralSerializer(new StandardConverter());
32+
$jws = $serializer->unserialize($input);
33+
$split = $jws->split();
34+
35+
self::assertEquals(3, $jws->countSignatures());
36+
self::assertEquals(3, count($jws->split()));
37+
38+
for ($i = 0; $i < $jws->countSignatures(); $i++) {
39+
$signature1 = $jws->getSignature($i);
40+
$tempJws = $split[$i];
41+
self::assertEquals(1, $tempJws->countSignatures());
42+
self::assertEquals($jws->isPayloadDetached(), $tempJws->isPayloadDetached());
43+
self::assertEquals($jws->getEncodedPayload(), $tempJws->getEncodedPayload());
44+
self::assertEquals($jws->getPayload(), $tempJws->getPayload());
45+
46+
$signature2 = $tempJws->getSignature(0);
47+
self::assertEquals($signature1->getSignature(), $signature2->getSignature());
48+
self::assertEquals($signature1->getHeader(), $signature2->getHeader());
49+
self::assertEquals($signature1->getEncodedProtectedHeader(), $signature2->getEncodedProtectedHeader());
50+
self::assertEquals($signature1->getProtectedHeader(), $signature2->getProtectedHeader());
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)