-
Notifications
You must be signed in to change notification settings - Fork 424
DPoP: send dpop_jkt on /authorize (RFC 9449 §10 code binding) #4106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,7 @@ public enum DPoPProofBuilderError: Int, Error { | |
| case jwkExportFailed = 1 | ||
| case serializationFailed = 2 | ||
| case signingFailed = 3 | ||
| case thumbprintFailed = 4 | ||
| } | ||
|
|
||
| /// Builds an RFC 9449 §4 DPoP proof JWS for a single token-endpoint request. | ||
|
|
@@ -97,6 +98,36 @@ public final class DPoPProofBuilder: NSObject { | |
| return "\(signingInput).\(signatureSegment)" | ||
| } | ||
|
|
||
| /// RFC 7638 JWK thumbprint of a P-256 EC public key. | ||
| /// | ||
| /// Computes: `base64url(SHA-256(canonical_json({crv:"P-256", kty:"EC", x:<...>, y:<...>})))` | ||
| /// where `canonical_json` is UTF-8, no whitespace, keys in lexicographic order. | ||
| /// | ||
| /// Used at `/authorize` time to bind the authorization code to the same DPoP | ||
| /// key pair that will prove possession at `/token` (RFC 9449 §10 authorization | ||
| /// code binding via `dpop_jkt`). | ||
| /// | ||
| /// - Parameter publicKey: The P-256 `SecKey` whose thumbprint to compute. | ||
| /// Same key that will later populate the DPoP proof header's `jwk` claim. | ||
| /// - Returns: 43-character base64url string (SHA-256 hash, base64url-encoded, no padding). | ||
| /// - Throws: `DPoPProofBuilderError.jwkExportFailed` if `Encryptor.jwkP256` fails; | ||
| /// `DPoPProofBuilderError.thumbprintFailed` if canonicalization or hashing fails. | ||
| @objc public static func jwkThumbprint(publicKey: SecKey) throws -> String { | ||
| let jwk: [String: String] | ||
| do { | ||
| jwk = try Encryptor.jwkP256(from: publicKey) | ||
| } catch { | ||
| throw DPoPProofBuilderError.jwkExportFailed | ||
| } | ||
| // RFC 7638: canonical JSON with lexicographic key ordering, UTF-8, no whitespace. | ||
| guard let canonicalData = try? JSONSerialization.data(withJSONObject: jwk, | ||
| options: [.sortedKeys, .withoutEscapingSlashes]), | ||
| let digest = (canonicalData as NSData).sfsdk_sha256() else { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in f60327e — added the RFC 7638 §3.2 minimality note tying the thumbprint's correctness to |
||
| throw DPoPProofBuilderError.thumbprintFailed | ||
| } | ||
| return (digest as NSData).sfsdk_base64UrlString() | ||
| } | ||
|
|
||
| // MARK: - Helpers | ||
|
|
||
| /// 96 bits (12 bytes) of random entropy, per backend design doc. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: RFC 7638 §3.2 requires the canonical JSON to contain only the required members for the key type — for P-256 that's exactly
{crv, kty, x, y}, no optional fields likekid,use, orkey_ops.jwkis passed directly toJSONSerializationhere, so ifEncryptor.jwkP256ever grows extra fields the thumbprint will silently diverge from what the server computes off the DPoP proof'sjwkclaim, breaking the authorize↔token binding. The fixture test would catch it, but worth a comment stating the invariant in-context so the dependency is visible to a futurejwkP256author.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in f60327e — added the RFC 7638 §3.2 minimality note tying the thumbprint's correctness to
jwkP256's output staying at exactly{crv, kty, x, y}, and aSFSDKCoreLogger.wline before thethumbprintFailedthrow so canonicalization failures are diagnosable.