14
14
use TrueLayer \Signing \Constants \TrueLayerSignatures ;
15
15
use TrueLayer \Signing \Contracts \Verifier as IVerifier ;
16
16
use TrueLayer \Signing \Exceptions \InvalidAlgorithmException ;
17
+ use TrueLayer \Signing \Exceptions \InvalidArgumentException ;
17
18
use TrueLayer \Signing \Exceptions \InvalidSignatureException ;
18
19
use TrueLayer \Signing \Exceptions \InvalidTrueLayerSignatureVersionException ;
19
20
use TrueLayer \Signing \Exceptions \RequestPathNotFoundException ;
22
23
23
24
final class Verifier extends AbstractJws implements IVerifier
24
25
{
26
+ /**
27
+ * @var JWSSerializerManager
28
+ */
25
29
private JWSSerializerManager $ serializerManager ;
30
+
31
+ /**
32
+ * @var JWSVerifier
33
+ */
26
34
private JWSVerifier $ verifier ;
27
- private JWK $ jwk ;
35
+
36
+ /**
37
+ * @var array<JWK>
38
+ */
39
+ private array $ jwks ;
28
40
29
41
/**
30
42
* @var string[]
31
43
*/
32
44
private array $ requiredHeaders = [];
33
45
46
+ /**
47
+ * @param array<string, string> ...$jsonObjects
48
+ *
49
+ * @return IVerifier
50
+ * @throws InvalidArgumentException
51
+ */
52
+ public static function verifyWithJsonKeys (array ...$ jsonObjects ): IVerifier
53
+ {
54
+ $ jwks = [];
55
+ try {
56
+ foreach ($ jsonObjects as $ jsonObject ) {
57
+ $ encoded = json_encode ($ jsonObject );
58
+ if (!is_string ($ encoded )) {
59
+ throw new InvalidArgumentException ('One or multiple keys are invalid ' );
60
+ }
61
+
62
+ $ jwks [] = JWK ::createFromJson ($ encoded );
63
+ }
64
+ } catch (\InvalidArgumentException $ e ) {
65
+ throw new InvalidArgumentException ('One or multiple keys are invalid ' );
66
+ }
67
+
68
+ return new self ($ jwks );
69
+ }
70
+
71
+ /**
72
+ * @param JWK ...$jwks
73
+ *
74
+ * @return IVerifier
75
+ */
76
+ public static function verifyWithKeys (JWK ...$ jwks ): IVerifier
77
+ {
78
+ return new self ($ jwks );
79
+ }
80
+
34
81
/**
35
82
* @param JWK $jwk
36
83
*
37
- * @return Verifier
84
+ * @return IVerifier
38
85
*/
39
- public static function verifyWithKey (JWK $ jwk ): Verifier
86
+ public static function verifyWithKey (JWK $ jwk ): IVerifier
40
87
{
41
- return new self ($ jwk );
88
+ return self :: verifyWithKeys ($ jwk );
42
89
}
43
90
44
91
/**
45
- * @param string $pem
92
+ * @param string ...$pems
46
93
*
47
- * @return Verifier
94
+ * @return IVerifier
95
+ * @throws InvalidArgumentException
48
96
*/
49
- public static function verifyWithPem (string $ pem ): Verifier
97
+ public static function verifyWithPem (string ... $ pems ): IVerifier
50
98
{
51
- $ jwk = JWKFactory::createFromKey ($ pem , null , [
52
- 'use ' => 'sig ' ,
53
- ]);
99
+ $ jwks = [];
100
+ try {
101
+ foreach ($ pems as $ pem ) {
102
+ $ jwks [] = JWKFactory::createFromKey ($ pem , null , [
103
+ 'use ' => 'sig ' ,
104
+ ]);
105
+ }
106
+ } catch (\Exception $ e ) {
107
+ throw new InvalidArgumentException ('One or multiple PEM keys could not be deserialized ' );
108
+ }
54
109
55
- return new self ($ jwk );
110
+ return new self ($ jwks );
56
111
}
57
112
58
113
/**
59
- * @param string $pemBase64
114
+ * @param string ...$pemsBase64
60
115
*
61
- * @return Verifier
116
+ * @return IVerifier
117
+ * @throws InvalidArgumentException
62
118
*/
63
- public static function verifyWithPemBase64 (string $ pemBase64 ): Verifier
119
+ public static function verifyWithPemBase64 (string ... $ pemsBase64 ): IVerifier
64
120
{
65
- return self ::verifyWithPem (\base64_decode ($ pemBase64 ));
121
+ $ decodedPems = [];
122
+ foreach ($ pemsBase64 as $ pemBase64 ) {
123
+ $ decodedPems [] = \base64_decode ($ pemBase64 );
124
+ }
125
+
126
+ return self ::verifyWithPem (...$ decodedPems );
66
127
}
67
128
68
129
/**
69
- * @param string $path
130
+ * @param string ...$paths
70
131
*
71
- * @return Verifier
132
+ * @return IVerifier
133
+ * @throws InvalidArgumentException
72
134
*/
73
- public static function verifyWithPemFile (string $ path ): Verifier
135
+ public static function verifyWithPemFile (string ... $ paths ): IVerifier
74
136
{
75
- $ jwk = JWKFactory::createFromKeyFile ($ path , null , [
76
- 'use ' => 'sig ' ,
77
- ]);
137
+ $ jwks = [];
78
138
79
- return new self ($ jwk );
139
+ try {
140
+ foreach ($ paths as $ path ) {
141
+ $ jwks [] = JWKFactory::createFromKeyFile ($ path , null , [
142
+ 'use ' => 'sig ' ,
143
+ ]);
144
+ }
145
+ } catch (\Exception $ e ) {
146
+ throw new InvalidArgumentException ('One or multiple files contain invalid keys ' );
147
+ }
148
+
149
+ return new self ($ jwks );
80
150
}
81
151
82
152
/**
83
- * @param JWK $jwk
153
+ * @param array< JWK> $jwks
84
154
*/
85
- private function __construct (JWK $ jwk )
155
+ private function __construct (array $ jwks )
86
156
{
87
- $ this ->jwk = $ jwk ;
157
+ $ this ->jwks = $ jwks ;
88
158
$ this ->serializerManager = new JWSSerializerManager ([new CompactSerializer ()]);
89
159
$ this ->verifier = new JWSVerifier (new AlgorithmManager ([new ES512 ()]));
90
160
}
91
161
92
162
/**
93
163
* @param string[] $headers
94
164
*
95
- * @return $this
165
+ * @return IVerifier
96
166
*/
97
- public function requireHeaders (array $ headers ): Verifier
167
+ public function requireHeaders (array $ headers ): IVerifier
98
168
{
99
169
\array_push ($ this ->requiredHeaders , ...$ headers );
100
170
@@ -126,10 +196,14 @@ public function verify(string $signature): void
126
196
throw new InvalidAlgorithmException ();
127
197
}
128
198
129
- if ($ jwsHeaders ['tl_version ' ] !== TrueLayerSignatures::SIGNING_VERSION ) {
199
+ if (! empty ( $ jwsHeaders [ ' tl_version ' ]) && $ jwsHeaders ['tl_version ' ] !== TrueLayerSignatures::SIGNING_VERSION ) {
130
200
throw new InvalidTrueLayerSignatureVersionException ();
131
201
}
132
202
203
+ if (empty ($ jwsHeaders ['kid ' ])) {
204
+ throw new InvalidSignatureException ('The kid is missing from the signature headers ' );
205
+ }
206
+
133
207
$ tlHeaders = !empty ($ jwsHeaders ['tl_headers ' ]) ? \explode (', ' , $ jwsHeaders ['tl_headers ' ]) : [];
134
208
$ normalisedTlHeaders = Util::normaliseHeaderKeys ($ tlHeaders );
135
209
foreach ($ this ->requiredHeaders as $ header ) {
@@ -138,8 +212,12 @@ public function verify(string $signature): void
138
212
}
139
213
}
140
214
141
- if (!$ this ->verifier ->verifyWithKey ($ jws , $ this ->jwk , TrueLayerSignatures::SIGNATURE_INDEX , $ this ->buildPayload ($ tlHeaders ))) {
142
- throw new InvalidSignatureException ();
215
+ foreach ($ this ->jwks as $ jwk ) {
216
+ if ($ this ->verifier ->verifyWithKey ($ jws , $ jwk , TrueLayerSignatures::SIGNATURE_INDEX , $ this ->buildPayload ($ tlHeaders ))) {
217
+ return ;
218
+ }
143
219
}
220
+
221
+ throw new InvalidSignatureException ();
144
222
}
145
223
}
0 commit comments