Skip to content

Commit 8350a28

Browse files
committed
Add first draft of JKT check.
1 parent 8afcdc6 commit 8350a28

File tree

1 file changed

+59
-2
lines changed

1 file changed

+59
-2
lines changed

src/Utils/DPop.php

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,65 @@ private function validateJwtDpop($jwt, $dpopKey) {
116116
throw new InvalidTokenException('JWT Confirmation claim (cnf) is missing Thumbprint (jkt)');
117117
}
118118

119-
if ($cnf['jkt'] !== $dpopKey) {
120-
throw new InvalidTokenException('JWT Confirmation claim (cnf) provided Thumbprint (jkt) does not match Key ID from JWK header');
119+
// !!! HIER GEBLEVEN !!!
120+
121+
// @CHECKME: If we are checking against the JKT this "if" can be removed
122+
if ($dpopKey !== '') {
123+
$keyTypes = [
124+
/*ES256*/ 'EC' => ['crv', 'kty', 'x', 'y'],
125+
/*RS256*/ 'RSA' => ['e', 'kty', 'n'],
126+
];
127+
128+
$jwk = $jwt->headers()->get('jwk');
129+
130+
$keyType = $jwk['kty'];
131+
132+
if (array_key_exists($keyType, $keyTypes) === false) {
133+
$message = vsprintf('Unsupported key type "%s". Must be one of: %s', [
134+
$keyType,
135+
implode(', ', array_keys($keyTypes)),
136+
]);
137+
throw new InvalidTokenException($message);
138+
}
139+
140+
$required = $keyTypes[$keyType];
141+
$missing = array_diff($required, array_keys($jwk));
142+
143+
if ($missing !== []) {
144+
throw new InvalidTokenException('Required JWK values have not been set: ' . implode(', ', $missing));
145+
}
146+
147+
/**
148+
* RFC7638 defines a method for computing the hash value (or "digest") of a JSON Web Key (JWK).
149+
*
150+
* The resulting hash value can be used for identifying the key represented by the JWK
151+
* that is the subject of the thumbprint.
152+
*
153+
* For instance by using the base64url-encoded JWK Thumbprint value as a key ID (or "kid") value.
154+
*
155+
* @see https://www.rfc-editor.org/rfc/rfc7638
156+
*
157+
* The thumbprint of a JWK is created by:
158+
*
159+
* 1. Constructing a JSON string (without whitespaces) with the required keys in alphabetical order.
160+
* 2. Hashing the JSON string using SHA-256 (or another hash function)
161+
*
162+
*/
163+
// @FIXME: Add logic to build correct JSON string
164+
$json = vsprintf('{"e":"%s","kty":"%s","n":"%s"}', [
165+
$jwk['e'],
166+
$jwk['kty'],
167+
$jwk['n'],
168+
]);
169+
170+
$hash = hash('sha256', $json);
171+
$encoded = Base64Url::encode($hash);
172+
173+
// @FIXME: What are we comparing against? JKT? KID / $dpopKey?
174+
if ($encoded !== $dpopKey /* or $cnf['jkt'] ?*/) {
175+
// @CHECKME: What error message belongs here?
176+
throw new InvalidTokenException('JWT Confirmation claim (cnf) provided Thumbprint (jkt) does not match Key ID from JWK header');
177+
}
121178
}
122179

123180
//@FIXME: add check for "ath" claim in DPoP token, per https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop#section-7

0 commit comments

Comments
 (0)